设计模式总结

一、创建型模式(Creational Patterns)

1. 工厂方法(Factory Method)
1.1 意图(Intent):

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
定义一个用于创建对象的接口,但是让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

  • 工厂方法中的角色:
    Product:抽象产品
    ConcreteProduct:具体产品
    Factory:抽象工厂
    ConcreteFactory:具体工厂
1.2 适用场景:

(1)如果无法预知对象的确切类别及其依赖关系时,可以考虑使用工厂方法;
工厂方法将创建产品的代码与实际使用产品的代码分离,从而能在不影响其他代码的情况下,扩展创建产品部分的代码;
(2)如果你希望用户能扩展你的软件库或框架的内部组件,可使用工厂方法;
(3)如果你希望使用现有对象来节省系统资源,而不是每次都重新创建对象,可使用工厂方法;
工厂方法可以返回缓存、对象池或其他来源的已有对象。

1. 优点
  1. 避免创建者和具体产品之间的紧密耦合;
  2. 单一职责原则:将产品创建代码放在程序的单一位置,从而使代码更容易维护;
  3. 开闭原则:无须改变现有的客户端代码,就可以在程序中引入新的产品类型;
  • 缺点
  1. 需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。
2. 抽象工厂(Abstract Factory)
  • 意图(Intent):
    Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
    提供一个创建一系列相关或相互依赖的对象的接口,而无需指定它们具体的类。
  • 抽象工厂中的角色
    抽象工厂(Abstract Factory)
    具体工厂(Concrete Factory)
    抽象产品(Abstract Product)
    ——声明同一种类型的产品接口;
    具体产品(Concrete Product)
    —— 定义一个被相应的具体工厂创建的产品对象。
  • 适用场景:
    简单工厂模式针对的是一个产品等级结构(即继承自同一种抽象产品的体系),而抽象工厂针对的是多个产品等级结构。
    对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
  • 优缺点:
    ① 分离了具体的类;
    ② 可以很方便的动态更换产品族
    只要更换具体工厂,就可以做到更换产品族(product families),因为一个具体工厂会创建一整个产品族(a complete family of products)。
    系统中有多于一个的产品族,而每次只使用其中某一个产品族。
    ③ 有利于保持产品的一致性
    属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
    ④ 添加新的产品类型比较困难,因为AbstractFactory接口确定了所有可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及AbstractFactory及其所有子类的更改。
    当Abstract Factory模式中每一种具体工厂类只创建一个产品对象时,也就是只存在一个产品体系结构时,退化为Factory Method模式;
    当Factory Method模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建对象,并将创建对象的工厂设计为静态方法时,就退化为Simple Factory模式;
3. 生成器(Builder)

意图(Intent):
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
将一个复杂对象的构建(construction )与它每一过程中的实现细节分离,使得同样的构建过程可以创建(create)出不同类型(types )和形式(representations)的产品对象。


image.png
4. 原型(Prototype)

意图(Intent):
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

5. 单例(Singleton)

意图(Intent):
Ensure a class only has one instance, and provide a global point of access to it.
保证一个类仅有一个实例,并提供一个访问它的全局访问点。

二、结构型模式(Structural Patterns)

6. 适配器(Adapter)

6.1 Intent
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
将一个类的接口转化成客户端希望的另一个接口。Adaper模式使得接口不兼容的类可以一起工作。
6.2 与其它模式的关系:

  • Bridge VS Adapter
    Bridge模式通常会于开发前期进行设计, 使你能够将程序的各个部分独立开来以便开发。 而Adapter模式通常在已有程序中使用, 让相互不兼容的类能很好地合作。


    Adapter Pattern.png
  • Adaper VS Decorator
    Adapter修改了已有对象的接口;
    Decorator则是在不改变对象接口的情况下,强化(enhance)了其功能。
    Decorator还支持递归组合,而Adapter则无法实现。

  • Adapter VS Proxy VS Decorator
    Adapter为被封装对象(wrapped object)提供了不同的接口;
    Proxy则为其提供了相同的接口,Decorator则能为其提供加强的接口(enhanced interface)。

  • Facade VS Adapter
    Facade为已有对象定义了一个新接口,而Adaper则尽力使得已有接口可复用。Adapter通常只封装一个对象, 而Facade通常作用在整个子系统的对象上。

  • Bridge VS State VS Strategy
    他们的共同点是都基于组合来实现代码结构。

7. 桥接(Bridge)

Decouple an abstraction from its implementation so that the two can vary independently.
将抽象部分与它的实现部分分离,使两者可以独立的变化。
当在两个独立维度的层次结构中使用继承扩展类时,将导致代码复杂程度指数增长。桥接模式通过将继承改为组合的方式来解决这个问题。 具体来说, 就是抽取其中一个维度、只持有它的抽象引用,具体的实现部分可以动态替换。
适用场景:

  1. 如果你想要拆分或重组一个具有多重功能的庞杂类 (例如能与多个数据库服务器进行交互的类), 可以使用桥接模式。
    类的代码行数越多, 弄清其运作方式就越困难, 对其进行修改所花费的时间就越长。 一个功能上的变化可能需要在整个类范围内进行修改, 而且常常会产生错误, 甚至还会有一些严重的副作用。
    桥接模式可以将庞杂类拆分为几个类层次结构。 此后, 你可以修改任意一个类层次结构而不会影响到其他类层次结构。 这种方法可以简化代码的维护工作, 并将修改已有代码的风险降到最低。
  2. 如果你希望在几个独立维度上扩展一个类, 可使用该模式。
    桥接建议将每个维度抽取为独立的类层次。 初始类将相关工作委派给属于对应类层次的对象, 无需自己完成所有工作。
  3. 如果你需要在运行时切换不同实现方法, 可使用桥接模式。
解决方案
Bridge Pattern.png
8. 组合(Composite)

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
将对象组合成树状结构、以表示“部分-整体”的层次结构。Composite使得用户可以相同的方式对待单个对象和复杂对象的组合(容器对象)。

9. 装饰(Decorator)

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
通过将对象(Wrappee Object)放入特殊封装对象(Wrapper Objects)为原对象增加新的行为。


Decorator pattern.png
10. 外观(Facade)

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
为包含许多活动部件的复杂子系统提供一个简单的接口。Facade定义了一个更高层次的接口、使得子系统更加易用。

11. 享元(Flyweight)

Use sharing to support large numbers of fine-grained objects efficiently.
享元是一种结构型设计模式, 它允许你在消耗少量内存的情况下支持大量对象。模式通过共享多个对象的部分状态来实现上述功能。 换句话来说, 享元会将不同对象的相同数据进行缓存以节省内存。

12. 代理(Proxy)

Provide a surrogate or placeholder for another object to control access to it.
为源对象提供一个替代品或占位符,以实现对源对象的控制。
代理模式适合应用场景:

  1. 延迟初始化(虚拟代理)
    如果你有一个偶尔使用的重量级服务对象,一直保持该对象运行会消耗系统资源时,可使用代理模式。
  2. 访问控制(保护代理)
    如果你只希望特定客户端使用服务对象,这里的对象可以是操作系统中非常重要对的部分,而客户端则是各种已启动的程序(包括恶意程序),此时可使用代理模式。代理可仅在客户端凭据满足要求时将请求传递给服务对象。
  3. 本地执行远程服务(远程代理)
    适用于服务对象位于远程服务器上的情形,代理通过网络传递客户端请求,负责处理所有与网络相关的复杂细节。
  4. 记录日志请求(日志记录代理)
    适用于当你需要保存对于服务对象的请求历史记录时。 代理可以在向服务传递请求前进行记录。
  5. 缓存结果代理(缓存代理)
    适用于需要缓存客户请求结果并对缓存生命周期进行管理时, 特别是当返回结果的体积非常大时。代理可对重复请求所需的相同结果进行缓存, 还可使用请求参数作为索引缓存的键值。
  6. 智能引用
    代理会将所有获取了指向服务对象或其结果的客户端记录在案。 代理会时不时地遍历各个客户端, 检查它们是否仍在运行。 如果相应的客户端列表为空, 代理就会销毁该服务对象, 释放底层系统资源。
  • 与其它模式的关系
    Adaper能为封装对象(wrapped object)提供不同的接口;Proxy能为封装对象提供相同的接口;Decorator则能为之提供加强的接口。
    Facade与Proxy的相似之处在于它们都缓存了一个复杂实体( complex entity)并且按照自己的方式进行实例化;不同之处是代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换。
    Decorator与Proxy的不同之处在于代理通常自行管理其服务对象的生命周期,然后Decorator中装饰器的组合通常用客户端来控制。

三、行为模式(BehavioralPatterns)

13. 职责链(Chain Of Responsibility)

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
职责链允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
责任链会将特定行为(particular behaviors)转化为称为处理者(handles)的独立对象。模式建议你将这些处理者连成一条链。 链上的每个处理者都持有下一处理者的引用(reference)。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直至所有处理者都有机会对其进行处理。处理者可以决定不再沿着链传递请求, 这可高效地取消所有后续处理步骤。

14. 命令(Command)

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
将一个请求封装为一个对象,从而使可以将请求作为函数的参数传递、延迟请求执行或者将其放入队列中、记录请求日志,以及支持撤销操作。

15. 解释器(Interpreter)

Given a language, define a represention for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
给定一种语言,定义它的语法的一种表示,同时定义一个解释器(interpreter),该解释器使用定义好的语法表示(grammar represention)来解释语言中的句子。

16. 迭代器(Iterator)

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
在不暴露一个聚合对象(aggregate object)的内部表示形式的情况下,有序访问集合中的各个元素。
Iterator的主要思想是将集合的遍历行为提取为称为iterator的独立对象。
应用场景:

  1. 当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑), 可以使用迭代器模式。
  2. 使用该模式可以减少程序中重复的遍历代码。
  3. 如果你希望代码能够遍历不同的甚至是无法预知的数据结构, 可以使用迭代器模式。
17. 中介者(Mediator)

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
用一个中介对象来封装一系列对象的交互。Mediator使得各对象不需要显式的相互引用,从而使其松散耦合,而且可以独立地改变它们之间的交互。
中介者让一个程序的不同组件(components)通过特殊的Mediator对象进行间接的沟通,从而减少组件间的相互依赖。
中介者让你能在单个中介者对象中封装多个对象间的复杂关系网。类所拥有的依赖关系越少,就越易于修改、扩展和复用。

适用场景:

  1. 当一些对象和其他对象紧密耦合以致难以对其进行修改时,可使用中介者模式;
  2. 当组件因过于依赖其他组件,而无法在不同应用中复用时,可使用中介者模式;
  3. 如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者模式。
18. 备忘录(Memento)

Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原来保存的状态。

19. 观察者(Observer)

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

20. 状态(State)

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
允许一个对象在它的内部状态改变时改变其行为,使其看上去就行改变了自身所属的类一样。
该模式将与状态相关的行为抽取到独立的状态类中, 让原对象将工作委派给这些类的实例, 而不是自行进行处理。


State pattern.png
21. 策略(Strategy)

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。

22. 模板方法(Template Method)

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
应用场景:
当你希望客户端只是扩展某个特定的步骤、而不是整个算法或其结构时,可使用模板方法模式。
在将算法转化为模板方法时,你可将相似的步骤提取到超类中以去除重复的代码,子类间各不同的代码可继续保留在各子类中。
实现方式:

  1. 分析目标算法,确定能否将其拆分为多个步骤,从所有子类的角度出发,考虑哪些步骤能够通用,哪些步骤各不相同;
  2. 创建抽象基类并声明一个模板方法、和代表算法步骤的一系列抽象方法,在模板方法中根据算法结构依次调用相应步骤,可用final修饰模板方法以防止子类对其进行重写。
  3. 虽然可将所有步骤全都设为抽象类型, 但默认实现可能会给部分步骤带来好处, 因为子类无需实现那些方法。
  4. 可考虑在算法的关键步骤之间添加钩子。
  5. 为每个算法变体新建一个具体子类, 它必须实现所有的抽象步骤, 也可以重写部分可选步骤。
23. 访问者(Visitor)

Represent an operation to be performed on the elements of an object structure.Visitor lets you define a new operation without changing the classes of the elements on which it operates.
允许你在不修改已有代码的情况下,向已有类层次结构中增加新的行为。
Visitor模式建议将新行为放在一个称为Visitor的独立类中,而不是试图将其整合到已有类中。需要执行操作的源对象(original object )将作为参数传递给Visitor的方法的,从而使改方法能访问源对象的一切必要数据。
Visitor类可以定义一组 (而不是一个) 方法, 且每个方法可接收不同类型的参数。


visitor_pattern.png

实现方式:

  1. 在Visitor接口中声明一组“访问”方法,分别对应程序中的每个具体元素类;
  2. 声明Element接口,在其中添加“accept”方法,接收一个Visitor对象作为参数。
  3. 在所有具体的Concrete Element类中实现“accept”方法,这些方法必须将调用重定向到Visitor对象的的visitXXX方法中,其中visitXXX方法的参数为当前的Concrete Element类。

你可能感兴趣的:(设计模式总结)