0%

设计模式

GitHub - Luo25177/Design-Pattern

介绍

设计原则

  1. 依赖倒置原则
    • 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定),稳定的东西不应该依赖于变化的东西
    • 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定),稳定的东西不应该依赖于变化的东西
    • 解决: 创建抽象类,之后的类依赖抽象类
    • 依赖:例如A依赖B,在编译A的时候只有B存在才能编译成功 编译式依赖
  2. 开放封闭原则
    • 对扩展开放,对更改关闭
    • 类模块应该是可以扩展的,但是不可以修改
  3. 单一职责原则
    • 一个类应该仅有一个引起它变化的原因,一个类不能放太多功能,也就是不能有太多的责任
    • 变化的方向隐含着类的责任
  4. Liskov替换原则
    • 子类必须能够替换它们的基类(is-a)
    • 继承表达类型抽象
  5. 接口隔离原则
    • 不应该强迫客户程序依赖他们不用的方法
    • 接口应该小而完备
    • 真正有必要暴漏出去的方法才做成 public
  6. 优先使用对象组合而不是类继承
    • 类继承通常为”白箱复用”,对象组合通常为”黑箱复用”
    • 继承在某种程度上破坏了封装性,子类父类耦合度高,父类对子类开放的太多
    • 而对象组合只要求被组合的对象具有良好定义的接口,耦合度比较低
  7. 封装变化点
    • 使用封装来创建对象之间的分界层,让设计者可以在分界层一侧进行修改,而不会对另一侧的产生不良影响,从而出现高层次的封装
  8. 针对接口编程,而不是针对实现编程
    • 不将变量类型声明为某个特定的具体类,而是声明为某个接口
    • 客户程序无需获取对象的具体类型,只需要知道对象所具有的接口
    • 减少系统中各部分的依赖关系,从而实现”高内聚,松耦合”的类型设计方案

设计模式是为了让程序具有更好的

  1. 代码重用性,相同功能的代码不用多次编写
  2. 可读性,编程规范性,便于其他程序员阅读和理解
  3. 可扩展性,当需要增加新的功能时,非常方便
  4. 可靠性,当我们增加新的功能时对原来的功能没有影响

设计模式七大原则

  1. 单一职责原则
    一类代码只负责一项职责
    提高类的可读性可维护性
    降低变更引起的风险
  2. 接口隔离原则
    客户端不应该依赖不需要的接口,即一个类对另一个类的依赖应该建立最小的接口上
  3. 依赖倒转(转置)原则
    高层模块不应该依赖底层模块
    抽象不应该依赖细节,抽象的相较于细节的比较稳定
    中心原则面向接口编程
  4. 里氏替换原则
    子类中尽量不要重写父类的方法
  5. 开闭原则
    当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是修改代码,对扩展开放,对修改关闭
  6. 迪米特法则
    一个类除了对外提供的public方法以外,不对外泄露任何信息
    只与直接的朋友通信
    降低类之间的耦合程度
  7. 合成复用原则
    尽量使用合成/聚合的方式,而不是使用继承

抽象向下

  1. 封装
  2. 继承
  3. 多态

基类的析构函数写成虚函数

C++的四种转换类型

const_cast

去掉类型的 const 或者 volatile 属性

  • const_cast<目标类型>(标识符)

static_cast

无条件转换,静态类型转换

  • 基类和子类之间的转换:其中子类指针转化为父类指针是安全的,但是父类指针转换为子类指针是不安全的
  • 基本数据类型转换, enum,struct,int char,float 等, static_cast 不能进行无关类型(如非基类和子类)指针之间的转换
  • 把任何类型的表达式转化为 void 类型
  • static_cast 不能去掉类型的 constvolatile 属性

dynamic_cast

有条件转换,动态类型转换,运行时检查类型安全(转换失败返回null)

  • 有条件转换,动态类型转换,运行时检查类型安全(转换失败返回NULL):
  • 将一个基类对象指针(或引用) cast 到继承类指针, dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理, 即会作出一定的判断。
  • 若对指针进行 dynamic_cast ,失败返回 null ,成功返回正常 cast 后的对象指针;
  • 若对引用进行 dynamic_cast ,失败抛出一个异常,成功返回正常 cast 后的对象引用。
  • dynamic_cast 在将父类cast到子类时,父类必须要有虚函数,否则编译器会报错。
  • dynamic_cast 主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
  • 在类层次间进行上行转换时, dynamic_cast和static_cast 的效果是一样的;
  • 在进行下行转换时, dynamic_cast 具有类型检查的功能,比 static_cast 更安全。

reinterpret_cast

仅重新解释类型,但是没有进行二进制的转换

  • 仅重新解释类型,但没有进行二进制的转换:
  • 转换的类型必须是一个指针,应用、算术类型、函数指针或者成员指针。
  • 在比特级别上进行转换,可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。但不能将非 32bit 的实例转成指针。
  • 最普通的用途就是在函数指针类型之间进行转换。
  • 很难保证移植性。

类的继承特点

类成员\继承方式 public继承 protected继承 private继承
基类的public成员 派生类的public成员 派生类的protected成员 派生类的private成员
基类的protected成员 派生类的protected成员 派生类的protected成员 派生类的private成员
基类的private成员 在派生类中不可见 在派生类中不可见 在派生类中不可见

友元

友元函数: 如果在本类以外的其他地方定义的函数, 在类体重用 friend 进行声明. 此函数就称为本类的有元函数, 友元函数可以访问这个类中的私有成员

友元类: 类 A 将另一个类 B 声明为其友元类, 友元类 B 中的所有函数都是 A 类的友元函数, 可以访问 A 类中的所有成员

  • 友元关系不能被继承。
  • 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
  • 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明。

面向对象设计模式

子类可以使用父类指针来表示,所以类一般都声明为指针,指针具有多态性,变量要声明成基类,虚函数是运行时依赖。

c++ 中构造函数如果调用虚函数的话就是一种静态绑定,不是动态绑定,原因:如果在基类的构造函数中调用虚函数的话,那么在子类创建时会先调用基类的构造函数,基类的构造函数会调用子类重写的虚函数,那就会造成子类未完成构造函数但是却调用自身的虚函数,违背了规则。但是在其他的语言 jave,c# 中构造函数调用虚函数是一种动态绑定

模板类是编译式多态,虚函数是运行式多态,也就是说模板类运行时性能高于基于虚函数的类,有了泛型编程的迭代器就不再使用虚函数的迭代器了

组件协作模式

模板模式 template

20200406223604450.png

  • 封装不变的部分,将不变的部分抽取出来;
  • 扩展可变部分,将可变的设置抽象方法,让具体子类来实现。
  • 抽取的公共代码,便于后期维护
  • 行为有基类来控制,具体操作有子类实现。
    就是先定义一个通用的基类,然后在对应创建子类,子类复写基类的方法

策略模式 strategy

20200406223743348.png

  • 就是当遇到相同的目的的算法,但是每一个都不通用,就可以写一个基类算法来减少if-else语句的使用,子类的算法都是继承自基类
  • 基类写对应的算法的抽象,在子类里直接重载该算法
  • 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。使得算法可独立于使用它的客户程序而变化

观察者模式 observer

20200406223838139.png

对于一个持续运行的程序,需要用的另一个观察者的类来观察程序中运行的情况,可以随意添加多个观察者。创建一个基类观察者,子类观察者都依附于它,并且在对应的项目结构体中引用一个基类的观察者变量,之后可以转换为子类观察者

定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都能得到通知并自动更新

  • 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标于观察者,从而使二者之间的依赖关系达到松耦合
  • 目标发出通知时,无需指定观察者,通知会自动传播
  • 观察者会自己决定是否需要订阅通知,目标对象对此一无所知

单一职责模式

装饰模式 decrote

20200405220429862.png

创建一个基类,然后在基类的基础上创建装饰类,各个装饰类里含有一个基类,可以之后传入装饰类里对应的类,类的多态,运行时装配

其实就是在创建基类,每一个子类和对应的装饰都应该依赖于基类,可以创建一个装饰者基类,让所有的装饰者都依赖于它,在装饰者里可以引用一个基类,以便在使用的时候可以转化为其他的装饰类或者是其他的子类。

动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator 模式比生成子类(继承)更为灵活(消除重复代码 & 减少子类个数)

Decorator 模式应用的要点在于解决主体类在多个方向上的扩展功能

桥模式 bridge

20200406115540814.png

在设计中如果责任划分的不清晰,使用继承得到的加过往往是随着需求变化的,子类极具膨胀,同时充斥着重复代码,关键是划清责任

要实现一定的功能,但是每一个子类都继承自父类,但是不能够完全继承父类的所有功能,而子类的子类又要调用父类的其他功能,这时候就可以简化

就是对象间的组合关系,抽象的基类沿着各自的子类变化。Bridge 模式使用“ 对象间的组合关系 ”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化

对象创建模式

工厂模式 factory

20200406123133241.png

隔离类对象使用者和具体类型之间的耦合关系,同样要求这些“易变类”拥有“稳定的接口”。在创建对象时,尽量避免new,从而避免创建对象中的紧耦合,从而支持对象创建的稳定。定义一个创建对象的接口,让子类来决定实例化哪个类,使一个类延迟化实现,主要是针对没有什么关联性的对象的创建

工厂模式旨在解决“单个对象” 的需求变化,但是创建方法和参数相同

抽象工厂 abstract_factory

20200406143418783.png

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类

与工厂模式不同之处在于,可以处理一系列相互依赖的对象的创建工作,不同系列的对象之间不能互相依赖

原型模式 prototype

20200406145115826.png

相当于把工厂模式里的基类和工厂基类合并到一起,通过克隆自己来创建对象

与工厂模式的不同之处在于使用时创建一个原型对象,通过克隆原型对象来使用,使用原型实例创建指定对象种类,然后拷贝指定对象创建类型使用原型克隆的方法,可以灵活动态创建拥有某些稳定接口的新对象,所做的工作就是注册一个新的对象,然后再任何需要的地方 clone

使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象

构建器 builder

20200406151348724.png

在设计程序中,有时候面临着“一个复杂对象”的创建工作,通常各个部分的子对象用一定的算法构成,由于需求的变换子对象也经常面临着一些剧烈的变化,但是将他们组合到一起就会比较稳定。

提供一种封装机制来隔离出负载对象的各个部分的变化,将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示,构建过程是稳定的,但是创建的不同表示是动态的

将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)

缺点是难以应对“分步骤构建算法”的需求变动

对象性能模式

只有这两种模式是为了解决性能问题,降低对象创建个数

单件模式 singleton

20200406153527896.png

模式中的实例构造器可以设置为protected 以允许子类派生,模式一般不要支持拷贝构造方法和 clone 接口,因为这有可能导致多个对象实例,违背 Singleton 模式的初衷

面向对象设计模式使用抽象类来解决问题,但是有时候抽象类中的虚函数可能会带来巨大的成本,必须谨慎处理。在软件系统中,有些特殊的类必须保证他们在系统中只存在一个实例才能保证正确性以及良好的效率,处理方式:

  1. 单锁 会出现多线程时,代价太大
  2. 双检查锁 会出现内存读写 reorder 解决方法: c++11 出现 volite 关键字来避免该变量创建时 reorder

享元模式 flyweight

20200406154613171.png

采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态(最好状态不可更改)的处理

创建之后对象状态不能更改,要注意对象状态的处理,尽可能实现只读的方式,在系统中采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行代价,运用共享的技术有效的支持大量细粒度的对象。

其实就是把创建过的对象放入对象池中,但是有些对象是不支持享元模式的,就是防止重复创建,有些对象被多个对象使用就没必要重复创建浪费空间了,可以只创建一个存入对象池中,如果已经创建了就不再创建而是调用之前创建好的

接口隔离模式

在组建构建过程中,某些接口之间直接依赖常常会带来很多问题,采用添加一层间接接口(稳定)来隔离本来相互紧密关联的接口,软件设计的核心是间接思想

门面模式 facade

20200406164137493.png

为子系统中的一组接口提供一个一致(稳定)的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用(复用)(隔离变化和稳定)

防止外部的对象与命令的对象直接紧耦合,所以提出间接层,添加接口来把客户类与内部系统本身的类隔离起来,以至于外部看不到内部的对象,最终的实现上无论内部怎么改变,但是外部所看到的接口是不变的,简化了外部系统与内部的交互。

facade 设计模式组件的内部应该是“相互耦合关系比较大的一系列组件”,而不是一个简单功能的集合,从客户程序的角度看,该模式简化了整个组件系统的接口,对于组件内部与外部客户程序来说,达到了一种“解耦”的效果,内部子系统的任何变化不会影响到接口的变化。

代理模式 proxy

20200406165510496.png

在面向对象时,有些对象由于某种原因(例如对象的创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,在不失去透明操作对象的同时来管理这些对象特有的复杂性为其他对象提供代理或者接口。

代理模式的实现方法或者实现粒度都相差很大,又可能对某个单个对象做copy之类的技术,实现细粒度的控制,也有可能对组件模块提供抽象代理层,在架构层做proxy

为其他对象提供一种代理以控制(隔离 ,即使用接口)对这个对象的访问

适配器 adapter

2020050113333475.png

适配器的目的就是为了移植不同类型的接口转移为其他的接口来达到实现接口匹配的配置,让原本接口不匹配的类可以一起工作

实际上组合一个类,支持实现的一个类,适配器就是为了改变一些旧的已经存在的类的接口来实现类的接口统一

public 继承是共有接口, protect,private 都是实现继承,但是不继承接口

中介者 mediator

20200406173151833.png

用一个中介对象来封装(封装变化)一系列的对象交互。中介者使各对象不需要显式的相互引用(编译时依赖 -> 运行时依赖 ),从而使其耦合松散(管理变化),而且可以独立地改变它们之间的交互

在软件构建过程中,经常会出现多个对象互相交互关联的情况,就是两个类相互依赖或者紧密依赖,而且这种引用关系经常会面临不断地变化,这种情况下可以使用一个中介者来改善类之间的紧耦合关系 从而来抵御改变的类

用一个中介类来封装一系列的对象交互(封装变化),中介者使各个对象之间不需要显示的相互引用(编译式依赖),转变为运行式依赖,而且可以独立的改变它们之间的交互,主要是为了解决对象之间直接的耦合关系。可以提供一个中介,让参与这些相互依赖的对象之间减少紧耦合,这个中介与这些对象需要时相互依赖的关系,以后需要相互调用的时候,就可以先调用中介通过中介来调用对应的目标,但是者之间需要一个通用的调用消息规范。中介中可以添加观察者模式,宗旨就是直接依赖关系转化为相互依赖关系。facade 解决的是系统内与系统外的隔离,中介者解决的是系统内类之间的依赖关系,多个对象出现各种依赖原则

状态变化模式

状态模式 State

20200406202242155.png

在组建构建过程中,某些对象的状态经常发生变化,对这些变化要进行有效的管理并且高层不受影响,软件构件过程中,某些对象的状态的改变其行为也会随之改变,状态类型也会发生改变

state模式将所有与一个特定状态相关的行为都放入一个state的子类对象中,在对象状态切换时,切换相应的对象,但是同时维持state的接口,这样实现了具体操作与状态转换之间的解耦,为不同的状态引入不同的对象使得状态转变变得更加明确,而且保证不会出现不一致的情况,因为转换是原子性的,要么彻底转换过来,要么不转换

在之后就没必要更改已经写好的状态器,但是可以不断地新增加子类,内部可以无限变化,但是对于外部的接口是固定的,不用太过于计较它们之间的差异性,需要注意它们之间共同的东西,把共同的相似的东西结合到一起,如果state没有实例变量,那么各个上下文可以共享同一个state对象,从而节省对象的开销

备忘录 Memento

20200406203835970.png

在软件构造中,某些对象的状态转换中,可能由于某些需求,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后可以把对象恢复到这个原先保存的状态

备忘录存储原发起对象内部状态,在需要时回复原发器的状态,核心是信息隐藏,即原发器需要对外部隐藏信息,也要保持封装性,同时又要把状态保存到外界。

采用效率较高,又容易正确实现的序列化方案来实现Memento模式

数据结构模式

在一些组件内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用,这时候将这些特定的数据结构封装在内部,在外部提供一些统一的接口来实现与特定数据结构无关的访问

组合模式 composite

20200406205814663.png

在软件某些情况下,客户代码过多的依赖与对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来代码维护性,扩展性等弊端。

方式:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性(稳定)

Composite 模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转换为“一对一”的关系,使得客户的代码可以一致的(复用)处理对象和对象容器,无需关心处理的是单个的对象还是组合的对象容器,客户代码将与纯粹的抽象接口而不是对象内部的实现结构,从而更能对应变化,其实就是一种多类型的递归调用

迭代器 iterator

20200406211152758.png

迭代器,在软件构建过程中,集合对象内部结构常常变化各异,但对于这些集合对象,我们希望在不爆露其内部结构的同时,可以让外部的客户代码透明的访问其中包含的元素,同时这种透明遍历为同一种算法在多种集合对象中进行操作提供了可能,提供一种方法顺序访问一个集合对象中的各种元素,而又不暴露该对象内部的实现

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露(稳定)该对象的内部表示

通过迭代器来隔离实现与应用,访问一个对象无需暴漏其内部表示,迭代堕胎,为遍历不同的集合结构体重一个统一的接口,从而支持同样的算法在不同的遍历结构上进行操作,遍历时有必要关注迭代器自身的问题,可能会导致问题

职责链 Chain of Resposibilty

20200406212924906.png

相当于是链表,在软件构件过程中,一个请求可能被多个对象处理,但是每个请求在运行中只能有一个接收者,如果显式制定的话,就会形成紧耦合,请求时不指定具体的接收者,使多个对象都有机会处理请求,避免请求的发送者和接收者之间的紧耦合关系,将这些对象连成一条链,就相当于一个链表,沿着这条链处理请求,直到有对象都处理完请求

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止

职责链的应用场景在于一个请求可能有多个接收者,但是最终的接收者只有这一个这时候请求发送者与接收者的耦合可能出现”变化脆弱“的症状吗,所以需要解耦合

行为变化模式

在组件构建过程中,组件行为的变化经常导致组件本身剧烈的变化,行为变化模式将组件之间的行为和变化解耦合,从而支持组件行为的变化,实现两者之间的松耦合

命令模式 Command

20200406214504166.png

在软件构建过程中,行为请求者与行为实现者通常呈现出紧耦合的关系,但在某些场合,比如需要对行为进行记录,撤销,事务等处理,这种无法抵御变化的紧耦合是不合适的,将请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及可以撤销的操作

将一个请求(行为)封装为一个对象,从而使你可用不同的请求对客户进行参数化。对请求排队或记录请求日志,以及支持可撤销的操作

根本的目的是将行为请求者与行为实现者解耦,在面向对象中,常见的手段是将行为对象抽象为对象,实现Command接口的具体命令对象具体的command有时候需要保存一些额外的状态信息,同时在使用命令模式的同时也可以使用composite模式将多个指令封装

访问器 Visitor

20200406220227848.png

在软件构件的过程中,由于需求的改变,其次是类结构层次中常常需要增加新的行为或者方法,如果直接在基类中更改,对子类来说是一种负担,会破坏原有设计,再不更改类结构层次的条件下在运行时透明的添加新的行为动作, visitor 主要是利用双重分发,在不更改原先类的层次结构时透明的为各个类动态的添加功能

表示一个作用于某对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)

缺点:在需要基类稳定的同时,也需要相关的子类也要稳定,visitor类想要写下来时需要基类的所有子类必须确定下来并且稳定,需要确定它们的数目,visitor基类稳定的前提时element所有子类都需要稳定,这个模式的条件极其苛刻

领域规则模式

在特定领域中,某些变化虽然频繁,但是可以抽象为某种规则,这时候结合特定领域,将问题抽象为语法规则,从而给出在该领域下的一般性解决方法

解析器 Interpreter

20200406222304558.png

将领域内的问题表达为某种语法规则下的句子,然后构建一个解释器来解释遮掩的句子,在这个领域内,只要符合这个规则,解释器就能够解释,从而达到解决问题的目的

interpreter模式的应用场合时interpreter的难点,只有满足业务规则频繁变化并且类似的结构不断出现并且容易抽象为语法规则问题才适合使用interpreter模式
使用interpreter模式来表示文法规则,从而可以使面向对象技巧来方便的扩展文法,比较适合简单的文法表示,对于复杂的文法表示interpreter会产生较大的类层次接口,需要求助于语法分析生成器额工具

两种手段分解&抽象

重构技巧

  • 静态→动态
  • 早绑定→晚绑定
  • 继承→组合,组合一个指针,可以指向该类的子类,是一种松耦合,指针指向是灵活的
  • 编译时依赖→运行时依赖
  • 紧耦合→松耦合

设计模式的宗旨:管理变化,提高服用

不用设计模式的情况:

  1. 代码可读性很差
  2. 需求理解还很浅
  3. 变化没有显现
  4. 不是系统的关键依赖点
  5. 项目没有复用价值
  6. 项目将要发布时

经验之谈

  1. 不要为模式而模式
  2. 关注抽象类&接口
  3. 清理变化点和稳定点
  4. 审视依赖关系
  5. 要有Framework和Application的区域隔离思维
  6. 良好的设计是演化的结果

概述

设计模式 定义
Template 定义一个抽象的基类,并且其中定义了一类系统的特定的统一的方法,然后在子类里分别复写里面的某些方法,还可以实现子类自己的特定的方法
Strategy 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
Observer 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都能得到通知并自动更新
Decorator 通过对象组合来给一个对象增加一些额外的职责,生成比子类更加灵活
Bridge 将一个具有多个特点的类进行分离,每种特点都自成一类,各自可以独立的变化。最后组合到一起
Factory 定义一个用于创建对象的接口,让子类决定实例化哪一个类。延迟类的实现
Abstract Factory 提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类
Prototype 先创建一些原型类的实例,然后通过拷贝这些原型来创建新的对象
Builder 将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。类似于构建过程相同但是其中的步骤不一致,就能构建出不同的对象
Singleton 一个类只有一个实例,并且提供一个全局访问的点
Flyweight 运用共享技术使得有效地支持大量细粒度的对象
Facade 为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
Proxy 为某一对象提供一种代理以控制对这个对象的访问,隔离接口,使用代理的接口,并且可以在代理中添加一些其它的功能。只能做一个对象的代理
Mediator 用一个中介对象来封装(封装变化)一系列的对象交互。中介者使各对象不需要显式的相互引用(编译时依赖 → 运行时依赖 ),从而使其耦合松散(管理变化),而且可以独立地改变它们之间的交互
Adapter 将一个类的接口转成客户希望的另一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
Memento 在不破环封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态
State 允许一个对象在其内部状态改变时改变它的行为,从而使对象看起来似乎修改了其行为
Composite 将对象组合成树形结构以表示部分-整体的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性(稳定)
Iterator 提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示
Chain of Responsibility 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止
Command 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。对请求排队或记录请求日志,以及支持可撤销的操作
Visitor 表示一个作用于某对象结构中的各元素的操作。使得可以在不改变各元素的类的前提下定义作用于这些元素的新操作
Interpreter 给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子