一、引言
1.1 设计模式的编目
- Abstract Factory: 提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- Adapter: 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- Bridge: 将抽象部分与它的实现部分分离,使它们都可以独立地变化。
- Builder: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- Chain of Responsibility: 为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
- Command: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。
- Composite: 将对象组合成树形结构以表示”部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。
- Decorator: 动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。
- Facade: 为子系统中的一组接口提供一个一致,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- Factory Method: 定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method是一个类的实例化延迟到其子类。
- Flyweight: 运用共享技术有效地支持大量细粒度的对象。
- Interpreter: 给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
- Iterator: 提供了一个方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
- Mediator: 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- Memento: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
- Observer: 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
- Prototype: 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
- Proxy: 为其他对象提供一个代理以控制对这个对象的访问。
- Singleton: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- State: 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。
- Strategy: 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。
- Template Method: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
- Visitor: 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
1.2 组织编目
1.3 怎样选择设计模式
二、创建型模式
2.1 Abstract Factory(抽象工厂)
2.1.1 类图
2.1.2 参与者
AbstractFactory
- 声明一个创建抽象产品对象的操作接口。
ConcreteFactory
- 实现创建具体产品对象的操作。
AbstractProduct
- 为一类产品声明一个接口。
ConcreteProduct
- 定义一个将被相应的具体工厂创建的产品对象。
- 实现AbstractProduct接口。
Client
- 仅使用由AbstractFactory和AbstractProduct类声明的接口。
2.1.3 协作
- 通常在运行时刻创建一个ConcreteFactory类的实例。这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工程。
- AbstractFactory将产品对象的创建延迟到它的ConcreteFactory子类。
2.2 Builder(生成器)
2.2.1 类图
2.2.2 参与者
Builder
- 为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder
- 实现Builder的接口以构造和装配该产品的各个部件。
- 定义并明确它所创建的表示。
- 提供一个检索产品的接口。
Director
- 构造一个使用Builder接口的对象。
Product
- 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
- 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
2.2.3 协作
- 客户创建Director对象,并用它所想要的Builder对象进行配置。
- 一旦产品部件被生成,导向器就会通知生成器。
- 生成器处理导向器的请求,并将部件添加到该产品中。
- 客户从生成器中检索产品。
交互图
2.3 Factory Method(工厂方法)
2.3.1 类图
2.3.2 参与者
Product
- 定义工厂方法所创建的对象的接口。
ConcreteProduct
- 实现Product接口。
Creator
- 声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteProduct对象。
- 也可以调用工厂方法以创建一个Product对象。
ConcreteCreator
- 重定义工厂方法以返回一个ConcreteProduct实例。
2.3.3 协作
- Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的ConcreteProduct实例。
2.4 Prototype(原型)
2.4.1 类图
2.4.2 参与者
Prototype
- 声明一个克隆自身的接口。
ConcretePrototype
- 实现一个克隆自身的操作。
Client
- 让一个原型克隆自身从而创建一个新的对象。
2.4.3 协作
- 客户请求一个原型克隆自身。
2.5 Singleton(单件)
2.5.1 类图
2.5.2 参与者
Singleton
- 定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作(C++中的一个静态成员函数)。
- 可能负责创建它自己的唯一实例。
2.5.3 协作
- 客户只能通过Singleton的Instance操作访问一个Singleton的实例。
三、结构型模式
3.1 Adapter(适配器)
3.1.1 类图
类版本
对象版本
3.1.2 参与者
Target
- 定义Client使用的与特定领域相关的接口。
Client
- 与符合Target接口的对象协同。
Adaptee
- 定义一个已经存在的接口,这个接口需要适配。
Adapter
- 对Adaptee的接口与Target接口进行适配。
3.1.3 协作
- Client在Adapter实例上调用一些操作。接着适配器调用Adaptee的操作实现这个请求。
3.2 Bridge(桥接)
3.2.1 类图
3.2.2 参与者
Abstraction
- 定义抽象类的接口。
- 维护一个指向Implementor类型对象的指针。
RefinedAbstraction
- 扩充由Abstraction定义的接口。
Implementor
- 定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
ConcreteImplementor
- 实现Implementor接口并定义它的具体实现。
3.2.3 协作
- Abstraction将client的请求转发给它的Implementor对象。
3.3 Composite(组合)
3.3.1 类图
3.3.2 参与者
Component
- 为组合中的对象声明接口。
- 在适当的情况下,实现所有类共有接口的缺省行为。
- 声明一个接口用于访问和管理Component的子组件。
- (可选)在递归结构中定义一个接口,用于访问一个父组件,并在合适的情况下实现它。
Leaf
- 在组合中表示叶节点对象,叶节点没有子节点。
- 在组合中定义图元对象的行为。
Composite
- 定义有子部件的那些部件的行为。
- 存储子部件。
- 在Component接口中实现与子部件有关的操作。
Client
- 通过Component接口操纵组合部件的对象。
3.3.3 协作
- 用户使用Component类接口与组合结构中的对象进行交互。如果接收者是一个叶节点,则直接处理请求。如果接收者是Composite,它通常将请求发送给它的子部件,在转发请求之前与/或之后可能执行一些辅助操作。
3.4 Decorator(装饰)
3.4.1 类图
3.4.2 对象结构示例图
3.4.3 参与者
Component
- 定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent
- 定义一个对象,可以给这个对象添加一些职责。
Decorator
- 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
ConcreteDecorator
- 向组件添加职责。
3.4.4 协作
- Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。
3.5 Facade(外观)
3.5.1 类图
3.5.2 参与者
Facade
- 知道哪些子系统类负责处理请求。
- 将客户的请求代理给适当的子系统对象。
Subsystem classes
- 实现子系统的功能。
- 处理由Facade对象指派的任务。
- 没有facade的任何相关信息;即没有指向facade的指针。
3.5.3 协作
- 客户程序通过发送请求给Facade的方式与子系统通信,Facade将这些消息转发给适当的子系统对象。尽管是子系统中的有关对象在做实际工作,但Facade模式本身也必须将它的接口转换成子系统的接口。
- 使用Facade的客户程序不需要直接访问子系统对象。
3.6 Flyweight(享元)
3.6.1 类图
3.6.2 对象结构示例图
3.6.3 参与者
Flyweight
- 描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
ConcreteFlyweight
- 实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
UnsharedConcreteFlyweight
- 并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
FlyweightFactory
- 创建并管理flyweight对象。
- 确保合理地共享flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
Client
- 维持一个对flyweight的引用。
- 计算或存储一个(多个)flyweight的外部状态。
3.6.4 协作
- flyweight执行时所需的状态必定时内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部对象则由Client对象存储或计算。当用户调用flyweight对象的操作时,将该状态传递给它。
- 用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyeightFactory对象得到ConcreteFlyweight对象,这可以保证对它们适当地进行共享。
3.7 Proxy(代理)
3.7.1 类图
3.7.2 对象结构示例图
3.7.3 参与者
Proxy
- 保持一个引用使得代理可以访问实体。若RealSubject和Subject的接口相同,Proxy会引用Subject。
- 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
- 控制对实体的存取,并可能负责创建和删除它。
其他功能依赖于代理的类型:
- Remote Proxy负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。
- Virtual Proxy可以缓存实体的附加信息,以便延迟对它的访问。
- Protection Proxy检查调用者是否具有实现一个请求所必须的访问权限。
Subject
- 定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
RealSubject
- 定义Proxy所代表的实体。
3.7.4 协作
- 代理根据其种类,在适当的时候向RealSubject转发请求。
四、行为模式
4.1 Chain of Responsibility(职责链)
4.1.1 类图
4.1.2 对象结构示例图
4.1.3 参与者
Handler
- 定义一个处理请求的接口。
- (可选)实现后继链。
ConcreteHandler
- 处理它所负责的请求。
- 可访问它的后继者。
- 如果可处理该请求,就处理;否则将该请求转发给它的后继者。
Client
- 向链上的具体处理者(ConcreteHandler)对象提交请求。
4.1.4 协作
- 当客户提交一个请求时,请求沿链传递直至有一个ConcreteHandler对象负责处理它。
4.2 Command(命令)
4.2.1 类图
4.2.2 参与者
Command
- 声明执行操作的接口。
ConcreteCommand
- 将一个接收者对象绑定于一个动作。
- 调用接收者相应的操作,以实现Execute。
Client
- 创建一个具体命令对象并设定它的接收者。
Invoker
- 要求该命令执行这个请求。
Receiver
- 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
4.2.3 协作
- Client创建一个ConcreteCommand对象并指定它的Receiver对象。
- 某Invoker对象存储该ConcreteCommand对象。
- 该Invoker通过调用Command对象的Execute操作来提交一个请求。若该命令是可撤销的,ConcreteCommand就在执行Execute操作之前存储当前状态已用于取消该命令。
- ConcreteCommand对象对调用它的Recevier的进行操作以执行该请求。
4.2.4 时序图
4.3 Interpreter(解释器)
4.3.1 类图
4.3.2 参与者
AbstractExpression(抽象表达式)
- 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
TerminalExpression(终结符表达式)
- 实现与文法中的终结符相关联的解释操作。
- 一个句子中的每个终结符需要该类的一个实例。
NonterminalExpression(非终结符表达式)
- 对文法中的每一条规则
R ::=R<sub>1</sub>R<sub>2</sub>...R<sub>n</sub>
都需要一个NonterminalExpression类。 - 为从
R<sub>1</sub>
到R<sub>n</sub>
的每个符号都维护一个AbstractExpression类型的实例变量。 - 为文法中的非终结符实现解释(Interpret)操作。解释(Interpret)一般要递归地调用表示
R<sub>1</sub>
到R<sub>n</sub>
的那些对象的解释操作。
Context
- 包含解释器之外的一些全局信息。
Client
- 构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
- 调用解释操作。
4.3.3 协作
- Client构建(或被给定)一个句子,它是NonterminalExpression和TerminalExpression的实例的一个抽象语法树,然后初始化上下文并调用解释操作。
- 每一个非终结符表达式节点定义相应子表达式的解释操作。而各终结符表达式的解释操作构成了递归的基础。
- 每一节点的解释操作用上下文来存储和访问解释器的状态。
4.4 Iterator(迭代器)
4.4.1 类图
4.4.2 参与者
Iterator
- 迭代器定义访问和遍历元素的接口。
ConcreteIterator
- 具体迭代器实现迭代器接口。
- 对该聚合遍历时跟踪当前位置。
Aggregate
- 聚合定义创建相应迭代器对象的接口。
ConcreteAggregate
- 具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。
4.4.3 协作
- ConcreteIterator跟踪聚合中的当前对象,并能够计算出待遍历的后继对象。
4.5 Mediator(中介者)
4.5.1 类图
4.5.2 对象结构示例图
4.5.3 参与者
Mediator
- 中介者定义一个接口用于与各同事(Colleague)对象通信。
ConcreteMediator
- 具体中介者通过协调各同事对象实现协作行为。
- 了解并维护它的各个同事。
Colleague class
- 每一个同事类都知道它的中介对象。
- 每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。
4.5.4 协作
- 同事向一个中介者对象发送和接受请求。中介着在各同事间适当地转发请求以实现协作行为。
4.6 Memento(备忘录)
4.6.1 类图
4.6.2 参与者
Memento
- 备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
- 防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者(caretaker)只能看到备忘录的窄接口——它只能将备忘录传递给其他对象。相反,原发器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生成本备忘录的那个原发器访问本备忘录的内部状态。
Originator
- 原发器创建一个备忘录,用以记录当前时刻它的内部状态。
- 使用备忘录恢复内部状态。
CareTaker
- 负责保存好备忘录。
- 不能对备忘录的内容进行操作或检查。
4.6.3 协作
- 管理器向原发器请求一个备忘录,保留一段时间后,将其送回给原发器。
4.6.4 时序图
4.7 Observer(观察者)
4.7.1 类图
4.7.2 参与者
Subject
- 目标知道它的观察者。可以有任意多个观察者观察同一目标。
- 提供注册和删除观察者对象的接口。
Observer
- 为那些在目标发生改变时需获得通知的对象定义一个更新接口。
ConcreteSubject
- 将有关状态存入各ConcreteObserver对象。
- 当它的状态发生改变时,向它的各个观察者发出通知。
ConcreteObserver
- 维护一个指向ConcreteSubject对象的引用。
- 存储有关状态,这些状态应与目标的状态保持一致。
实现Observer的更新接口以使自身状态与目标的状态保持一致。
4.7.3 协作
- 当ConcreteSubject发生任何可能导致其观察者与本身状态不一致的改变时,它将通知它的各个观察者。
- 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。
4.7.4 时序图
4.8 State(状态)
4.8.1 类图
4.8.2 参与者
Context
- 定义客户感兴趣的接口。
- 维护一个ConcreteState子类的实例,这个实例定义当前状态。
State
- 定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState subclasses
- 每一子类实现一个与Context的一个状态相关的行为。
4.8.3 协作
- Context将与状态相关的请求委托给当前的ConcreteState对象处理。
- Context可将自身作为一个参数传递给处理该请求的状态对象。这使得状态对象在必要时可访问Context。
- Context是客户使用的主要接口。客户可用状态对象来配置一个Context,一旦一个Context配置完毕,它的客户不再需要直接与状态对象打交道。
- Context或ConcreteState子类都可决定哪个状态是另外哪一个的后继者,以及是在何种条件下进行状态转换。
4.9 Strategy(策略)
4.9.1 类图
4.9.2 参与者
Strategy
- 定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
ConcreteStrategy
- 以Strategy接口实现某具体算法。
Context
- 用一个ConcreteStrategy对象来配置。
- 维护一个对Strategy对象的引用。
- 可定义一个接口来让Strategy访问它的数据。
4.9.3 协作
- Strategy和Context相互作用以实现选定的算法。当算法被调用时,Context可以将该算法所需要的所有数据都传递给该Strategy。或者,Context可以将自身作为一个参数传递给Strategy操作。这就让Strategy在需要时可以回调Context。
- Context将它的客户的请求转发给它的Strategy。客户通常创建并传递一个ConcreteStrategy对象给该Context;这样,客户仅与Context交互。通常有一系列的ConcreteStrategy类可供客户从中选择。
4.10 Template Method(模板方法)
4.10.1 类图
4.10.2 参与者
AbstractClass
- 定义抽象的原语操作(primitive operation),具体的子类将重定义它们以实现一个算法的各个步骤。
- 实现一个模板方法,定义一个算法骨架。该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。
ConcreteClass
- 实现原语操作以完成算法中与特定子类相关的步骤。
4.10.3 协作
- ConcreteClass靠AbstractClass来实现算法中不变的步骤。
4.11 Visitor(访问者)
4.11.1 类图
4.11.2 参与者
Visitor
- 为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
ConcreteVisitor
- 实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累计结果。
Element
- 定义一个Accept操作,它以一个访问者为参数。
ConcreteElement
- 实现Accept操作,该操作以一个访问者为参数。
ObjectStructure
- 能枚举它的元素。
- 可以提供一个高层的接口以允许该访问者访问它的元素。
- 可以是一个复合或是一个集合,如一个列表或一个无序集合。
4.11.3 协作
- 一个使用Visitor模式的客户必须创建一个ConcreteVisitor对象,然后遍历该对象结构,并用该访问者访问每一个元素。
- 当一个元素被访问是,它调用对应于它的类的Visitor操作。如果必要,该元素将自身作为这个操作的一个参数以便访问者访问它的状态。