Prototype 原型模式仍然属于“对象创建模式”模式的一种。前面两篇介绍的工厂方法模式和抽象工厂模式的流行程度要远大于
Prototype 原型模式和builder构建器模式,后两种由于较为简单,介绍篇幅也会少一些。
文章目录
- 1. 动机 (Motivation)
- 2. 代码演示Prototype 原型模式
- 2.1 Prototype.cpp
- 2.2 ConcretePrototype.cpp
- 2.3 Client
- 3. 模式定义
- 4. 结构
- 5. 要点总结
- 6. 其他参考
1. 动机 (Motivation)
- 在软件系统中,经常面临着
“某些结构复杂的对象”
的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。 - 如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?
与Factory Method工厂方法模式区别就在于“某些结构复杂的对象”
,利用深克隆将对象你想要的当前状态取出来,原型就可以实现传入的prototype状态是怎样就能深克隆一个出来,实现状态复杂对象的再现。
结构复杂的界定很难明确界定,使用Prototype 原型模式和Factory Method工厂方法模式的区别就是看是否Factory Method工厂方法模式可以很简便的创建对象,还是需要需要考虑对象复杂的中间状态,又希望保留该状态,如果是后者就使用Prototype 原型模式
。实际使用原型模式的场景很少。
Prototype 原型模式解决的问题是与Factory Method工厂方法模式一模一样的,也是有一些细微不同,属于Factory Method工厂方法模式的变体。
2. 代码演示Prototype 原型模式
2.1 Prototype.cpp
在C++设计模式_08_Factory Method工厂方法模式中可以看到Factory Method工厂方法对应的代码,Prototype 原型模式中将以下代码中的2个类合并起来。
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0;
virtual ~SplitterFactory(){}
};
变为以下形式:
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
virtual ISplitter* CreateSplitter()=0;
};
并修改类的名字得到:
Prototype.cpp
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ISplitter* clone()=0; //通过克隆自己来创建对象
virtual ~ISplitter(){}
};
2.2 ConcretePrototype.cpp
Factory Method工厂方法中FileSplitter2.cpp就变为以下形式:
ConcretePrototype.cpp
//具体类
class BinarySplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new BinarySplitter(*this);
}
};
class TxtSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new TxtSplitter(*this);
}
};
class PictureSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new PictureSplitter(*this);
}
};
class VideoSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new VideoSplitter(*this);
}
};
在C++中有着最成熟的克隆自己的方法就是拷贝构造函数,也就是上面的new TxtSplitter(*this)
,前提是你类的拷贝构造函数要写正确。
2.3 Client
Client也就是MainForm则变为:
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype=prototype;
}
void Button1_Click(){
ISplitter * splitter=
prototype->clone(); //克隆原型得到新对象
splitter->split();
}
};
有些人可能会想到将上面的splitter->split();
变为删除 ISplitter * splitter=prototype->clone(); //克隆原型
,变为prototype->split();
,这是不对的,因为原型对象是供克隆的,真正使用的时候需要创建出新的对象
,不能一直使用prototype原型对象。
以上即为Prototype 原型模式。
3. 模式定义
使用原型实例
指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
——《设计模式》GoF
“原型实例”就是在MainForm中的ISplitter* prototype;
,这里的“拷贝”是深克隆。
4. 结构
上图是《设计模式》GoF中定义的Prototype 原型模式的设计结构。结合上面的代码看图中最重要的是看其中稳定和变化部分,也就是下图中红框和蓝框框选的部分。
5. 要点总结
- Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”
- Prototype模式对于“如何创建易变类的实体对象”采用
“原型克隆”
的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”
的新对象一-所需工作仅仅是注册一个新类的对象 (即原型),然后在任何需要的地方Clone。 - Prototype模式中的Clone方法可以利用某些框架中的序列化来实现
深拷贝
。(其他语言中需要利用框架)
6. 其他参考
C++设计模式——原型模式