- 原型模式应对的是对象内部状态初始化的繁杂流程
- 直接深拷贝一个已经初始化好的实例,然后修改少量状态即可使用
- 构建模式把构建和类的状态、方法拆分开
“对象创建”模式
- 通过“对象创建” 模式绕开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#)