设计模式
-
“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”。
-
软件设计的金科玉律:复用。
-
面向对象设计最大的优势在于:抵御变化。
-
设计模式的假设是必须有稳定点(全都是稳定点的话,设计模式也失去意义)。
-
设计模式最大的作用是在变化和稳定中寻找隔离点,分离他们,从而管理变化。
面向对象设计原则
依赖倒置原则(DIP)
- 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定) 。
- 抽象(稳定)不应该依赖于实现细节(变化) ,实现细节应该依赖于抽象(稳定)。
- 依赖指的是编译时期的依赖,A依赖B -> B存在时A编译通过。
开放封闭原则(OCP)
- 对扩展开放,对更改封闭。
- 类模块应该是可扩展的,但是不可修改。
单一职责原则(SRP)
-
一个类应该仅有一个引起它变化的原因。
-
变化的方向隐含着类的责任。
Liskov 替换原则(LSP)
-
子类必须能够替换它们的基类(IS-A)。
-
继承表达类型抽象。
接口隔离原则(ISP)
-
不应该强迫客户程序依赖它们不用的方法。
-
接口应该小而完备。
优先使用对象组合,而不是类继承
- 类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
- 继承在某种程度上破坏了封装性,子类父类耦合度高。
- 而对象组合则只要求被组合的对象具有良好定义的接口,耦合
度低。
封装变化点
- 使用封装来创建对象之间的分界层,让设计者可以在分界层的
一侧进行修改,而不会对另一侧产生不良的影响,从而实现层
次间的松耦合。
针对接口编程,而不是针对实现编程
-
不将变量类型声明为某个特定的具体类,而是声明为某个接口。
-
客户程序无需获知对象的具体类型,只需要知道对象所具有的
接口。 -
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”
的类型设计方案。
重构关键技法
- 静态 -> 动态
- 早绑定 -> 晚绑定
- 继承 -> 组合
- 编译时依赖 -> 运行时依赖
- 紧耦合 -> 松耦合
Template Method
-
定义:定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。
-
Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的
某些特定步骤。 -
在具体实现方面,被Template Method调用的虚方法可以具有实
现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将
它们设置为protected方法。
Strategy
- 定义:定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户序(稳定)而变化(扩展,子类化)。
- Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。
- 含有许多条件判断语句的代码通常都需要Strategy模式。
- 有时候支持不使用的算法也是一个性能负担(if-else)。
Observer
- 定义:定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
Decorator
-
定义:动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消
除重复代码 & 减少子类个数)。 -
Decorator类在接口上表现为is-a Component的继承关系,即 Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用 另外一个Component类。
-
Decorator模式的目的并非解决“多子类衍生的多继承”问题, Decorator模式应用的要点在于解决“主体类在多个方向上的扩展 功能”——是为“装饰”的含义。
Bridge
- 定义:将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。
- Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固 有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。
对象创建模式
- 定义:通过“对象创建” 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
Factory Method
-
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。
-
Factory Method模式用于隔离类对象的使用者和具体类型之间的 耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导 致软件的脆弱。
-
Factory Method模式解决“单个对象”的需求变化。缺点在于要 求创建方法/参数相同。
Abstract Factory
-
定义:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类(家族工厂)。
-
“系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
Builder
- 定义:将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
Singleton
- 定义:保证一个类仅有一个实例,并提供一个该实例的全局访问点。
- Singleton中的实例构造器可以设置为protected以允许子类派生。
Flyweight
- 定义:运用共享技术有效支持大量细粒度的对象。
- Flyweight主要解决面向对象的代价问题。
Singleton
定义:保证一个类仅有一个实例,并提供一个该实例的全局访问点。
Singleton中的实例构造器可以设置为protected以允许子类派生。
Facade
- 定义:为子系统的一组接口提供一个一致(稳定)的界面。Facade模式定义了一个高层接口,这个接口使得系统更加容易使用。
Proxy
- 定义:对其他对象提供一种代理以控制(隔离,使用接口)对这个对象的访问。
Adapter
- 定义:将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
Mediator
- 定义:用一个中介对象来封装(封装变化)一系列的对象交互。中介者使各对象需要显示的相互引用(编译时依赖 -> 运行时依赖),从而使其耦合松散(管理变化),而且可以独立地改变它们之间的交互。
- 变“多个对象互相关联”为“多个对象和一个中介者关联”。
- Facade模式是解耦系统间(单向)的对象关联关系,Mediator模式是解耦系统内各个对象之间(双向)的关联关系。
State
- 定义:允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。
- 如果State对象没有实例变量,那么各个上下文可以共享一个State对象。
- 为不同的状态引入不同的对象使得状态转换变得更加明确。
Memento
- 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。
Composite
- 定义:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性(稳定)。
Iterator
- 定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露(稳定)该对象的内部表示。
Chain of Resposibility
- 定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
Command
- 定义:将一个请求(行为)封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
- 目的在于将“行为请求者”与“行为实现者”解耦。
- Command要求接口统一,functor可以不统一,functor性能较高。
visitor
- 定义:表示一个作用于某对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。
- Visitor模式通过所谓双重分发(double dispatch)来实现不更改(不添加新的操作-编译时)Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作(支持变化)。
- 最大缺点在于扩展类层次结构(Element),因此适用于Element类层次结构稳定,其中的操作却经常面临频繁改动。
Interpreter
- 定义:给定一种语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释预言中的句子。
- 应用场合:业务员规则频繁变化,且类似的结构不断出现,并且容易抽象成语法规则的问题。