设计模式·原型模式·构建模式

 

原型模式应对的是对象内部状态初始化的繁杂流程 直接深拷贝一个已经初始化好的实例,然后修改少量状态即可使用 构建模式把构建和类的状态、方法拆分开

  • 原型模式应对的是对象内部状态初始化的繁杂流程
    • 直接深拷贝一个已经初始化好的实例,然后修改少量状态即可使用
  • 构建模式把构建和类的状态、方法拆分开

“对象创建”模式

  • 通过“对象创建” 模式绕开new
    • 来避免对象创建(new)过程中所导致的紧耦合(依赖具体类)
    • 从而支持对象创建的稳定
    • 它是接口抽象之后的第一步工作
  • 典型模式
    • Factory Method
    • Abstract Factory
    • Prototype
    • Builder

原型模式

缘起 Motivation

  • 软件系统中,结构复杂对象的创建
    • 由于需求变化,这些对象有着剧烈的变化
    • 它们有稳定一致的对外接口
  • 如何向客户程序隔离这种变化?

原型设计

对象

class ISplitter{
public:
    virtual void split()=0;
    virtual ISplitter* clone()=0; //通过克隆自己来创建对象
    
    virtual ~ISplitter(){}

};

应用程序

class MainForm : public Form
{
    ISplitter*  prototype;//原型对象

public:
    MainForm(ISplitter*  prototype){
      // 原型对象只用来克隆,不能使用
        this->prototype=prototype;     
    }
    
	void Button1_Click(){
		ISplitter * splitter=
            prototype->clone(); //克隆原型
        
        splitter->split();
	}
};
  • 因为对象的结构复杂,每次用new创建需要进行大量成员的初始化工作
  • 原型模式直接使用初始化好的一个对象实例,以它的状态创建一个新实例,然后只需修改几个成员就可以使用

构建模式

动机(Motivation)

  • 在软件系统中,有时候面临着“一个复杂对象”的创建工作
    • 其通常由各个部分的子对象用一定的算法构成;
    • 由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定
    • 模板方法很像
  • 如何应对这种变化?
    • 如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化
    • 从而保持系统中的“稳定构建算法”不随着需求改变而改变?

初始设计

  • 游戏·建房子
    • 茅草房、砖房、豪华别墅
    • 流程相对是固定的
    • 不同房子的窗户、天花板的构建是不同的
  • 房子

    class House {
    public:
      void Init() {
        this->BuildPart1();
        for (i = 0; i < 4; i++) {
          this->BuildPart2();
        }
        bool flag = this->BuildPart3();
        if (flag) {
          this->BuildPart4();
        }
        this->BuildPart5();
      }
    protected:
      virtual void BuildPart1() = 0;
      virtual void BuildPart2() = 0;
      virtual void BuildPart3() = 0;
      virtual void BuildPart4() = 0;
      virtual void BuildPart5() = 0;
    };
    
    • 建房子的流程是固定的
    • 房子每个部分BuildPartx()是不同的
  • 对于具体的房子,可以继承这个接口,重写里面的各个步骤

    class StoneHouse: public House {
      // 重写各个虚函数
      BuildPart1() { ... }
    }
    
  • main函数中的调用流程

    int main() {
      House *pHouse = new StoneHouse();
      pHouse->init();
    }
    
  • Builder模式已经完成了,和模板方法很像

继续优化

  • 有的对象比较复杂
    • 除了构建流程以外
    • 还有其他复杂的状态要初始化
    • 可以把House自身的状态和功能和构建部分拆分开来
  • House拆分成
    • House(抽象基类)

      class House {
        ///....
      }
      
    • HouseBuilder

      class HouseBuilder {
        /******************************************
            抽象基类指针,可以指向所有子类中的某一个
            HouseBuilder可以方便的访问到House中的内容
        *******************************************/
      protect:
        House *pHouse;
      }
      
    • StoneHouseBuilder

      class StoneHouseBuilder: public HouseBuilder {
      protected:
        virtual void BuildPart1() {
          // pHouse->Part1 = ...
        }
      }
      
      • 可以方便的重写House中的内容
  • 构建过程单独提取出来

    class House {
      // House中其他复杂状态的初始化
    }
    
    • 与构建有关的过程提取到HouseBuilder中

      class HouseBuilder {
      public:
          House *GetResult() {
              return pHouse;
          }
          virtual ~HouseBuilder() {}
      
      protected:
          House *pHouse;
          virtual void BuildPart1() = 0;
          virtual void BuildPart2() = 0;
          virtual void BuildPart3() = 0;
          virtual void BuildPart4() = 0;
          virtual void BuildPart5() = 0;
      };
      
  • 新建一个建房负责人的类,专门负责建房

    • 里面组合HouseBuilder的指针
    • 把this换成HouseBuilder
    • 把Init()换成Construct
    class HouseDirctor {
    public:
      HouseBuilder *pHouseBuilder;
    
      HouseDirctor(HouseBuiler *pHouseBuilder) {
        this->pHouseBuilder = pHouseBuilder;
      }
    
      House *Construct() {
        pHouseBuilder->BuildPart1();
        for (i = 0; i < 4; i++) {
          pHouseBuilder->BuildPart2();
        }
        bool flag = pHouseBuilder->BuildPart3();
        if (flag) {
          pHouseBuilder->BuildPart4();
        }
        pHouseBuilder->BuildPart5();
    
        return pHouseBuilder->GetResult();
      }
    }
    
  • 对于具体的StoneHouse
    • 增加StoneHouse的抽象基类

      class StoneHouse : public House {
      };
      
    • 增加StoneHouseBuilder的具体实现类

      class StoneHouseBuilder : public HouseBuilder {
      protected:
          virtual void BuildPart1() {
              //pHouse->Part1 = ...;
          }
          virtual void BuildPart2() { }
          virtual void BuildPart3() { }
          virtual void BuildPart4() { }
          virtual void BuildPart5() { }
      };
      
  • 优点
    • 稳定的部分(抽象基类)
      • House
      • HouseBuilder
      • HouseDirctor
    • 变化部分
      • HouseBuilder
      • StoneHouseBuilder

模式定义

  • 将一个复杂对象的构建与其表示相分离
    • 使得同样的构建过程(稳定)可以创建不同的表示(变化)
  • House因为复杂,所以把House拆分成
    • 一部分是House本身这个类的状态和行为
    • 另一部分是专门构建House这个类的

类图

要点总结

  • Builder 模式主要用于“分步骤构建一个复杂的对象”
    • 在这其中 “分步骤”是一个稳定的算法
    • 而复杂对象的各个部分则经常变化
  • 变化点在哪里,封装哪里
    • Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动
    • 其缺点在于难以应对“分步骤构建算法”的需求变动
  • 在Builder模式中
    • 要注意不同语言中构造器内调用虚函数的差别 (C++ vs. C#)