设计模式
设计模式
设计模式六大原则: 开闭原则:一个软件实体入类、模块和函数应该对扩展开放,对修改关闭。即软件实体应该在不修改原有代码的情况下进行扩展 里氏替换原则:所有引用基类(父类)的地方必须能够透明的使用其子类的对象 依赖倒置原则:高层模块不应该依赖底层模块,二者都应该依赖其抽象:抽象不应该依赖细节;细节应该依赖抽象。换言之---要针对接口编程,而不是针对实现编程。 接口隔离原则:使用多个专门的接口,而不是用单一的总接口(不要把所有的代码放到一起),即客户端不应该依赖那些它不需要的接口。 迪米特法则:一个软件实体应当尽可能少的与其他实体发生相互作用 单一职责原则:不要存在多与一个导致类变更的原因。通俗的说,即一个类只负责一项职责
设计模式分类:
创建型模式:
1、工厂方法模式
2、抽象工厂模式
3、创建者模式
4、原型模式
5、单例模式
结构型模式:
1、适配器模式
2、桥模式
3、组合模式
4、装饰模式
5、外观模式
6、享元模式
7、代理模式
行为型模式:
1、解释器模式
2、责任链模式
3、命令模式
4、迭代器模式
5、中介者模式
6、备忘录模式
7、观察者模式
8、状态模式
9、策略模式
10、访问者模式
11、模板方法模式
简单的工厂模式:
内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化那一个产品类。
角色:
抽象工厂角色
具体工厂角色
抽象产品角色
具体产品角色
工厂方法模式相比简单的工厂模式将每个具体产品都对应了一个具体的工厂
适用场景:
需要生产多种、大量复杂对象的时候
需要降低耦合度的时候
当系统中的产品种类需要经常扩展的时候
优点:
每个具体产品都对应一个具体的工厂类,不需要修改工厂类代码
隐藏了对象创建的实现细节
缺点:
每增加一个具体产品类,就必须增加一个相应的具体工厂类
示例代码下一篇:这里只说理论以及思路
抽象工厂模式:
内容:定义一个工厂类的接口,让工厂子类来创建一系列相关或者是相互依赖的对象。
例如:生产一部手机,需要手机壳、cpu、操作系统三类对象进行组装,其中没类对象都有不同的种类,对于每个具体工厂,分别生产一部手机所需要的三个对象
角色:
抽象工厂模式
具体工厂模式
抽象产品角色
具体产品角色
客户端
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
适用场景:
系统要独立于产品的创建于组合的时候
强调一系列相关的产品对象的设计以便进行联合适用的时候
提供一个产品类库,隐藏的产品具体实现时
优点:
将客户端与类的具体实现相分离
每个工厂创建了一个完整的产品系列,使得易于交换产品系列
有利于产品的一致性(即产品之间的约束关系)
缺点:
难以支持新种类的(抽象)产品
建造者模式:
内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
角色:
抽象建造者
具体建造者
指挥者
产品
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
使用场景:
当创建复杂对象的算法应该独立与该对象的组成部分以及他们的装配方式时
当构造过程允许被构造的对象有不同的表示时
优点:
隐藏了一个产品的内部结构和装配过程
将构造代码与表示代码分开
可以对构造过程进行更精细的控制
单例模式:
内容:保证一个类只有一只实例,并提供一个访问它的全局访问点
角色:
单例
使用场景:
当类智能有一个实例而且客户可以从一个众所周知的访问点访问它的时候
优点:
对唯一实例的受控访问
单例相当于全局变量,但是防止了命名空间的被污染
与单例模式功能相似的概念:全局变量、静态变量(方法)
小结:
依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式、创建者模式
适配器模式:
内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能在一起工作的哪些类可以一起工作。
角色:
目标接口
待适配的类
适配器
两种实现方式:
类适配器:使用多继承
对象适配器:使用组合
使用场景:
想使用一个已经存在的类,而他的接口不符合你的要求
(对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它们的父类就扣
组合模式:
内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性 角色: 抽象组件(momponent) 叶子组件(leaf) 复合组件(composite) 客户端(client) 适用场景: 表示对象的“部分-整体”层次结构(特别是结构是递归的) 希望用户忽略组合对象与的单个对象的不同,用户统一地使用组合结构中的所有对象 优点: 定义了包含基本的对象和组合对象的类层次结构 简化了客户端的代码,即客户端可以一致地使用组合对象和单个对象 更容易增加新类型的组件 缺点: 很难限制组合中的组件
代理模式:
内容:为其他对象提供一种代理以控制这个对象的访问
角色:
抽象实体(subject)
实体(realsubject)
代理(proxy)
适用场景:
远程代理:为远程的对象提供代理
虚代理:根据需要创建很大的对象
保护代理:控制对原始对象的访问,用于对象有不同的访问权限的时候
优点:
远程代理:可隐藏对象位于远程地址空间的事实
虚代理:可以进行优化,例如根据需求创建对象
保护代理:允许在访问一个对象时有一些附加的内务处理
责任链模式:
内容:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
角色:
抽象处理者(handler)
具体处理者(concreteHandler)
客户端
eg:
请假部门批准:项目组组长→部门经理→总经理(一个没权限继续往上推)
JavaScript事件浮升机制(大的div抱着笑的div,笑的div有一个点击事件。。。)
适用场景:
有多个对象可以处理一个请求,那个对象处理由云翔时决定
在不明确接受者的情况下,向多个对象中的一个提交一个请求
优点:
降低耦合度:一个对象无需知道是其他那一个对象处理其请求
缺点:请求不保证被接收:链的末端没有处理或者是链的配置错误(比如上边的请假,总经理最后也没回复)
迭代器模式:
内容:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示 实现方法:__iter__、__next__ 略略略。。和函数中的迭代器一个意思
观察者模式:
内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象都得到通知并且被自动更新。观察者模式又称为(“发布-订阅”)模式 角色: 抽象主题(subject) 具体主题(concretesubject) --发布者 抽象观察者(observer) 具体观察者(concreteobserver) -- 订阅者 适用场景: 当一个抽象模型有两方面,其中一个方面依赖于另一个方面。将这两者封装在独立的对象中以使它们可以各自独立的改变和复用。 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。 当一个对象必须通知其它对象,而它又不能假定其他的对象是谁。换言之,你不希望这些对象时紧密耦合的。 优点: 目标和观察者之间的抽象耦合最小 支持广播通信 缺点: 多个观察者之间互不知道对方的存在,因此一个观察者对主题的修改可能造成错误的更新(这个缺点事实上是不存在的,比如说客户端服务端,客户端如果能修改服务端那还不炸了)
策略模式:
内容:定义一系列的算法,把它们一个个的封装起来,并且使它们可以相互替换。本模式使得算法可以独立于使用它的客户而变化。
角色:
抽象策略(strategy)
具体策略(concretestrategy)
上下文(context)
适用场景:
许多相关的类仅仅是行为有异
需要使用一个算法的不同变体
算法使用了客户端无需知道的数据
一个类中的多种行为以多个条件语句的形式存在,可以讲这些行为封装在不同的策略类中。
优点:
定义了一系列的可以重用的算法和行为
消除了一些条件语句
可以提供相同行为的不同实现
缺点:
客户必须了解不同的策略
策略与上下文之间的通信开销
增加了对象的数目
模板方法模式:
内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。
角色:
抽象类(AbstractClass):定义抽象的原子操作(钩子操作);实现一个模板方法作为算法的骨架
具体类(ConcreteClass):实现原子操作
适用场景:
一次性实现一个算法的不变得部分
各个子类中的公共行为应该被提取出来并且集中到一个公共父类中以避免代码重复
控制子类的扩展