引言
解决结构复杂对象的创建问题。
一个复杂对象,有着很多种状态。创建一个复杂对象,不仅需要创建初始状态,可能还要创建中间状态等等。针对创建初始状态,用构造函数即可(new一个对象即可);但new不能满足构造中间状态。
原型模式的代码
Prototype.cpp
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ISplitter* clone()=0; //通过克隆自己来创建对象
virtual ~ISplitter(){}
};
ConcretePrototype.cpp ```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); } };
3. 客户端Client.cpp
```cpp
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype=prototype;
}
void Button1_Click(){
//直接调用可以吗?
//prototype->split();
//不行!原型对象是供我们克隆用的,不能直接使用,否则就违背了原型设计模型的宗旨
//真正使用是需要创建一个新的对象
ISplitter * splitter= prototype->clone(); //克隆原型
splitter->split(); //再使用
delete splitter;
}
};
动机
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口
如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易用对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?
[2021/3/7理解] 其实就是我们想获得对象a
的克隆体,而new出来的对象是默认状态,和a
的状态不同(结构复杂就在这里体现),所以需要根据对象a来克隆一份。a就称之为原型
【工厂方法模式 与 原型模式 相比】
- 原型创建对象的方式,比工厂方法的灵活性更大。工厂方法只能创建初始状态的对象,而原型模式既可创建初始状态的对象,也可拷贝任意状态的对象
- 如何选择?
结构
要点总结
要点一:Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。
要点二:Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方clone
要点三:Prototype模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝
- 在某些语言中,如Java、C#,它们的深克隆和C++不一样,简单来讲,它们没有拷贝构造函数,它们可以通过序列化的方式实现深拷贝(在内存中先做一个序列化,再做一个反序列化)
- 在C++中,做序列化不是这么容易的,需要很多框架的搭配。但C++有一个便利的条件(拷贝构造函数),所以用拷贝构造函数来做Prototype模式比较方便