把《设计模式》1读薄

Design Patterns in a Nutshell

大三第一个学期有门叫“设计模式”的软件工程课,所以就预先整理一下自己对《设计模式》的一些笔记2,方便以后使用。

本份文档主要以简介各个模式实际含义为主,代码和结构简图为辅。

目录

创建型模式

Abstract Factory

在 factory 中提供获取具体对象的接口,将使用者(client)和组件的具体对象(实现)隔离。

// 提供对象实例
class AbstractFactory {
    public function createPartA();
    public function createPartB();
}

// factory, 组装对象
function makeSomething() {
    factory = new AbstractFactory();
    partA = factory->makePartA();
    partB = factory->makePartB();

    partA->usePartB(partB);

    return partA;
}

Builder

将对象的构建过程模板化成一系列操作,将构建过程和具体实现分离。

// 负责构建,各个部件在 builder 内完成组合。
class Builder {
    public function buildPartA();
    public function buildPartB();
    public function buildPartC();

    // 获取组装好的实例
    public function getInstance();
}

// 调用者
class Client {
    public function useInstance() {
        builder = new Builder();

        builder.buildPartA();
        builder.buildPartB();
        // 可自定义选择是否使用某一个组件
        // builder.buildPartC();

        instance = builder.getInstance();
    }
}

Factory Method

使用一个统一入口和配置来控制对象生成流程,对生成对象作定制。

function factory(settings) {
    if (settings.useImplementationA) {
        instance = new A();
    } else if (settings.useImplementationB) {
        instance = new B();
    } else {
        instance = new DefaultInstance();
    }

    if (settings.usePartC) {
        instance.usePartC(new C());
    }

    return instance;
}

Prototype

有高度血缘关系的对象之间使用克隆的方式来从一个基类衍生;对象之间采用一个接口来实现“基因变异”。

class BaseType {
    // 克隆一个对象
    public function clone();

    // 对象进行定制
    public function initialize(configs);
}

baseInstance = new BaseType();

instanceA = baseInstance.clone();
instanceA.initialize(configsA);

instanceB = baseInstance.clone();
instanceB.initialize(configsB);

Singleton

目标:保证一个类在全局都只有一个实例;实现方法:在这个类中只提供一个全局访问点来获取实例。

class Singleton {
    private _instance;

    // 外部获取对象的唯一接口
    public static function getInstance() {
        if (!_instance) {
            _instance = new Singleton();
        }

        return _instance;
    }

    public function methodA();
    public function methodB();
}

// 使用单例对象进行操作
Singleton::getInstance()->methodA();
Singleton::getInstance()->methodB();

结构型模式

Adapter

使用一个中间人来改变设计对象的接口使用方法。

client                   adapter                 target           
                                                                  
  +                        +                       +              
  |                        | method_a(a, b)        |              
  +----------------------> |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        +---------------------> |              
  |                        |                       |method_real(a)
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  +                        +                       +

Bridge

在原有的接口和实现之间多加一个抽象层(可能会改变调用的接口);使接口和实现之间松耦合;可以实现动态动态配置两者。

 interface          impl     
                             
+---+              +---+     
|   |  +---------> |   |     
+---+              +---+     
      bind tightly           
                             
interface                impl
          impl-interface     
+---+       +-+-+       +---+
|   | +---> |   | +---> |   |
+---+       +---+       +---+
          changes happens    
          here             

Composite

将层次结构中的不同结点进行一般化;通过 duck type 简化了使用者的复杂度。

不同结点:

  • 组合对象(根结点)
  • 单个对象(叶结点)
        +---+                                                              
        |   |                                                              
        +-+-+                                                              
          |           1. composite object holds interface like node object.
  +---------------+                                                        
  |       |       |   2. composite object has composite methods.           
  |       |       |                                                        
+-+-+   +-+-+   +-+-+                                                      
|   |   |   |   |   |                                                      
+---+   +---+   +-+-+                                                      
                  |                                                        
                  |                                                        
                +-+-+                                                      
                |   |                                                      
                +---+

Decorator

动态地为某个对象添加额外的功能。该方法比使用对象继承更加灵活(运行时执行)、成本更低。

注意点:

  • 可使用任意多个 decorator
  • decorate 后的对象需要和具体对象的接口保持一致,保证透明性
  • decorator 只能改变具体对象的外观行为;具体对象的内在行为可以通过 strategy 模式实现。
client                 decorators                target
                                                       
  +                    +   +  +                    +   
  |                    |   |  |                    |   
  +------------------> |   |  +------------------> |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  |                    |   |  |                    |   
  +                    +   +  +                    +

Facade

用一个统一的接口将子系统的复杂结构掩盖起来。子系统的使用、组合由 facade 来组织;调用者仅能使用 facade 提供的接口。

通常 facade 会用 singleton 的方式实现。

             +-----+     +-----+  client side                     
             |     |     |     |                                  
             +-----+     +-----+                                  
                XX         X                                      
                 XXX      XX                                      
                   XX   XXX                                       
                 +----------+                                     
+----------------+          +---------------+  "the hidden system"
|                +----------+               |                     
|                 XX  X                     |                     
|   +------+   XXXX   X                     |                     
|   |      XXXXX      X          +--------+ |                     
|   +------+          X          |        | |                     
|       XXX       +---X-----+ XXXXX-------+ |                     
|         XXXXXXXXX         |XX             |                     
|                 +---------+               |                     
|                                           |                     
+-------------------------------------------+

Flyweight

规模巨大小粒度元素抽取出来(放到一个池里面)供各个系统共享。

  • 内部状态:指一个 flyweight 本身的属性,可以给各个系统共享
  • 外部状态:指 flyweight 被一个系统使用后增加的新属性,不能被共享

Proxy

用一个代理将实际对象包裹起来,外部使用并不能察觉差异。可以在代理中实现对象的访问控制、延迟加载。

client                   proxy                  target           
                                                                  
  +                        +                       +              
  |                        | method_a(a, b)        |              
  +----------------------> |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        +---------------------> |              
  |                        |                       | method_a(a, b)
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  |                        |                       |              
  +                        +                       +

行为型模式

Chain of Responsibility

一系列组件串联对某一事件作出响应。

组件之间可以解耦:建立在默认可以不做响应,由后继来响应的默契上。

注意:最好能提供一个默认的最底部响应者,来保证能作出响应。

当某一处响应信息后即可停止传递。

Command

TODO

Interpreter

TODO

Iterator

使用一个统一接口的抽象对象来提供对 collection 内部元素的访问。

Mediator

由一个中介来处理各个部件之间的复杂关系。部件之间不需要知道对方的存在(不直接调用其他部件)。

Memento

使用一个内部对象来记录、恢复目标对象的状态;同时保证不会破坏对象的封装性。

Observer

pub-sub 实现

消息提醒模式:

  • push: 由发生者推送到监听者上
  • pull: 监听者从发生者中获取并筛选获取想要的
  • 中间人,broker: 用中间媒介来管理消息的获取和推送

State

将对象的内部状态放到一个状态实例中。由该实例来实现状态的定义和状态转移操作。

Strategy

将对象行为中易变的一部分外包分割出去,使其成为一系列可相互替代的实现(strategy)。

Template Method

在父类中定义一个固定的方法来调用其他一系列方法。子类继承的时候只需重载这些周边方法即可保持行为类似。

好莱坞法则、钩子函数。

Visitor

利用反射将复杂的操作转发到外部对象上。

class Element {
    public function methodA(VisitorInterface v)
    {
        v->visitElement(this);
    }
}

// 可以使用多个类似的 visitor
interface VisitorInterface {
    // 可以访问多个对象
    public function visitElement(Element e);
    public function visitOtherElement(Element e);
}

总结

设计模式是很难,难就难在没有一定代码积累量的话你根本不会察觉它存在的意义和价值。

设计模式也很易,因为你写够一定量代码再来看的话你总是会觉得自己曾几何时就创建过某个模式。

所以要多写代码,少谈主义。