深入理解设计模式(五):设计模式的总结
设计模式的总结
Design Pattern | What | Why | Examples | How | Functions |
---|---|---|---|---|---|
(Creational) | |||||
Abstract Factory | 提供了一个接口来创建相关的对象家族,而不用指定它们具体的 classes。 | 整体的改变多个 objects。 | 应用切换不同的外观(scroll bar,window,button) | Client 通过 FactoryProvider 获取一个 AbstractFactory 的子类实例,使用这个 Factory 去生产产品对象。 | 一致性 |
Builder | 将复杂对象的构造与其表现分开,因此相同的构造过程可以创建不同的表现。 | 不改变过程,构造不同的对象。 | 阅读器需要一个格式转换处理器对象,不同处理器可以转换不同的格式。不改变转换逻辑,增加新的转换处理器。 | Client 通过将不同的 Builder 子类实例传给 Director,然后通过调用 director 的construct()方法得到产品对象。 | 扩展性 |
Factory Method | 让一个类的实例化延迟到子类。 | 使用抽象对象维持关系,一个抽象类型的具体子类决定另一个抽象类型的具体子类。 | 文本编辑器不同的子应用创建不同的文档。只有当具体的子应用创建后,才知道要创建哪个文档类型实例。 | 不同的 Creator 子类生产不同的 Product 子类。Client 通过创建不同的 Creator 子类来创建不同的 Product 子类。 | 灵活性 |
Prototype | 通过拷贝这个 prototype 去创建新的对象。 | 想要重复创建类似的对象,且这个对象的创建过程比较复杂。 | 编辑音乐乐谱的应用,需要重复添加多个音符对象。 | Client 创建 Prototype 子类实例,然后调用它的 clone() 方法,得到这个类的对象拷贝。 | 复用性 |
Singleton | 确保一个 class 仅有一个实例,并且提供一个全局的访问它的方法。 | 有些 class 必须只有一个实例。 | 一个系统应该仅有一个文件系统和一个窗口管理器。 | 方法一:(饥饿式)直接创建静态的实例的成员变量。方法二:(懒惰式)定义一个同步的静态方法获取实例。方法三:(懒惰式)在内部类中定义一个静态的实例的成员变量。 | 唯一性 |
(Structural) | |||||
Adapter | 让不兼容的 classes 一起工作。Adapter 让 Adaptee 适应 Target。 | 一个不能兼容另一个接口的接口,希望他能够兼容。 | 画图编辑器有 lines, polygons, text 等元素。定义抽象的图形化接口 Shape,text 与 lines, polygons 有额外的操作,不同同时兼容一个接口。 | 方法一:(Object Adapter)Adapter 组合 Adaptee 。方法二:(Class Adapter)Adapter 实现 AdapteeImpl。 | 复用性 |
Bridge | 解耦抽象与它的实现,使它们可以独立地改变。 | 想要独立地修改、扩展,以及重用 abstraction 和 implementation。 | Window 有对应不同平台的子类,有不同特性的子类。都使用子类实现的话,需要多维度组合表示,难以添加新的子类。 | Client 通过将 implementation 子类实例作为参数,创建 abstraction 的子类实例。调用 abstract 对象的方法实际上是调用 implementation 的方法。 | 扩展性 |
Composite | 将对象组成树形结构以表示部分-整体层次结构。Composite 让 client 统一地对待单一对象和组合对象。 | 将多个 components 组成更大的 components,每个节点可以是单个组件,也可以是多个组件的组合,每个节点用统一的接口对象表示。 | 画图编辑器可以插入线、多边形和文字,可以插入图文。图文是图形和文字的组合。想把组合元素和单一元素统一对待,减少代码的复杂性。 | Composite 是 Component 的子类,它有一个 Component list 成员。Client 通过 new Composite() 来创建 Component 对象。 | 易用性,扩展性 |
Decorator | 动态地给一个 object 附加额外的职责。 | 有时我们想为 objects 添加职责,而不是整个 class。 | 为文本阅读器添加 border 或者 scroll 等。 | Client 创建一个 ConcreteComponent 对象,然后将对象作为参数,创建 Decorator 子类,调用 ConreteDecorator 对象是操作间接的调用 ConreteComponent 对象的操作。 | 扩展性 |
Facade | 为一个 subsystem 中的一组接口提供一个统一的接口,使得 subsystem 更容易使用。 | 将系统构建为子系统降低它的复杂性,并且,想要最小化系统之间的交流和依赖。 | Client 创建 Facade 实例,调用它的方法,它去调用子系统中的指定对象的方法。 | 易用性,松耦合 | |
Flyweight | 通过共享可以有效地支持大量细粒度的对象。 | 一个应用存在大量的相同的元素,如果每个元素都使用一个对象去表示,会造成空间的浪费。 | 文档编辑器中的相同的字符可以共享一个字符对象。 | Client 创建一个 FlyweightFactory,通过它来存储和去除共享的 Flyweight 对象。 | 复用性 |
Proxy | Proxy 为另一个对象提供了一个代理,去控制对这个对象的访问。 | 推迟对象的创建和初始化的全部花费,直到我们真正需要使用它。 | 文档中的大图片需要很长时间去加载,我们可以控制文档的加载,先加载所有文字,再加载图片。 | Client 通过 new ConcreteProxy() 创建 Subject 实例。Proxy 是 Subject 的子接口。ConcreteProxy 对象存在一个对 Subject 对象的引用。 | 灵活性 |
(Behavioral) | |||||
Chain of Responsibility | 通过给多个对象处理请求的机会,避免耦合请求发送者与接收者。 | 避免将请求者与具体的接收者绑定。 | Client 创建多个handler 将它们连接起来,把所有请求发送给第一个 handler。 | 松耦合、可扩展性 | |
Command | 将一个请求封装为一个对象,因此让你参数化客户端的不同请求。 | 有时需要发送一个请求给对象,但不知道任何关于请求的操作或者请求的接收者。 | Client 创建 Invoker,Receiver 对象和 Command 对象。receiver 对象作为参数构建 command 对象。执行命令先调用 invoker 的 setCommand() ,再调用requestExecute() 方法。 | 松耦合、可扩展性 | |
Interpreter | 给定一种语言,定义其语法表示形式,以及使用该表示形式来解释语言中的句子。 | 如果一个种特殊的问题经常发生,它可能值得用简单的语言将问题的实例表达为句子。我们可以构建 interpreter 通过解释这些句子来解决问题。 | Context 对象表示句子,TerminalExpression 对象可以解释 context。NonterminalExpression 对象可以连接 TerminalExpression 对象进行解释。 | 可扩展性 | |
Iterator | 提供以一种方法去顺序地访问聚合对象的元素,而不暴露它的底层表示。 | 访问它的元素而不暴露它的内部结构,提供统一的接口去遍历不同类型的聚合数据结构。 | Aggreate 子类可以创建对应 Iterator 子类,Iterator 实现顺序遍历。 | 灵活性 | |
Mediator | 定义一个对象去封装一组对象是如何交互。 | 大量的相互连接让系统的行为很难去改变。Mediator 可以用来控制和协调一组对象之间的交互。 | Mediator 作为参数创建不同的 ConcreteColleague 对象,colleague 之间的调用时通过调用 mediator 对象的方法实现。 | 松耦合、可扩展性 | |
Memento | 在不违反封装和外部化一个对象的内部状态等情况下,使得该对象可以在以后恢复之前的状态。 | 有时需要记录一个对象的内部状态。实现检查点和 undo 功能,让用户在发生错误时恢复状态记录的对象状态。 | caretaker 对象可以存储和删除 memento 对象,memento 对象保存了 originator 对象的状态,caretaker 可以设置不同的 memento 来恢复 originator 对象的状态。 | 可恢复 | |
Observer | 在对象中定义一对多的依赖,因此当一个对象改变状态时,所有它的依赖者是自动通知和更新的。 | 将系统划分为一组合作的 classes 常见的辅作用是需要维护相关对象之间的一致性。你不想通过使 classes 紧耦合来实现一致性,因为它降低了代码的可复用性。 | Subject 对象可以 attach Observer 对象,可以 detach Observer 对象。Subject 中存储了所有 attach 的 Observer对象的list,当 Subject 状态发送改变时,自动通知所有 attach 的 Observer 对象。 | 松耦合、可扩展性 | |
State | 当一个对象的内部状态改变时允许改变它的行为。 | 一个对象需要在不同的状态表现不同的行为。 | TCPConnection class 他表示一个网络连接。一个 TCPConnection object 可可能是多个不同状态中的一个,如:Established,Listening,Closed。当一个 TCPConnection 对象接收到请求时,它可以根据当前的状态进行响应。 | Context 对象设置不同的 State 对象,执行 request() 方法得到不同的结果。 | 可扩展性 |
Strategy | 定义一组算法,封装每一个,以及让它们是可互换的。 | 一个行为可能切换不同的实现方式。 | Context 配置不同的 Strategy 对象,执行不同的算法。 | 扩展性 | |
Template Method | 在操作中定义算法的骨架,将某些步骤推迟到子类。 | 通过使用抽象操作定义算法的某些步骤,模板方法可以固定其顺序,但可以让子类更改这些步骤以适合其需求。 | Client 通过 new ConcreteClass() 来创建 AbstractClass,ConcreteClass 实现了父类抽象步骤的方法。 | 复用性 | |
Visitor | Visitor 可以让你定义新的的操作,而无需更改其所操作的元素的类。 | 抽象父类定义了一组操作,不同的子类不一定需要实现所有的操作。所有操作放在所有子类中,会让人感到疑惑,以及难以维护。 | Client 定义一组 Element 对象,然后循环调用每个 Element 对象的 accept(Visitor visitor) 方法,可以对所有 Element 对象执行一个指定操作。 | 松耦合、可扩展性 |
设计模式的用途
设计模式常见的用途如下:
- 可复用性:减少冗余代码。
- 可扩展性:隔离职责,松耦合。很容易添加新类型的 class,容易添加新的功能。
- 灵活性:方便修改功能,少改动,独立修改。方便控制管理对象。
- 易用性:使得 Client 操作简单。
可复用性 | 可扩展性 | 灵活性 | 易用性 | 其他 |
---|---|---|---|---|
Prototype Adapter Flyweight Template Method |
Builder Bridge Decorator Chain of Responsibility Command Interpreter Mediator Observer State Strategy Visitor |
Factory Method Proxy Iterator |
Composite Facade |
Abstract Factory Singleton Memento |