设计模式 ProtoType 原型模式

动机

  • 在软件系统中,经常面临着"某些结构复杂的对象"的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
  • 如何应对这种变化?如何向"客户程序(使用这些对象的程序)"隔离出“这些易变对象”,从而使得依赖这些"易变对象"的客户程序不随着需求改变而改变。

举个例子:

找工作需要简历,以前没有打印机,都是手写很多份简历,且这些简历的内容都一样。但是如果要修改简历中的某项,所有写好的简历都的修改,工作量很大。有了打印设备之后。我们只需要手写一份,然后通过打印机复印多份即可。若要修改,只需修改原始版本,再去复印即可。原始的手写稿就相当与是一个原型,有了原型,就可以通过复印(拷贝)创造出更多的新简历。这就是原型模型的基本思想。

定义

  • 使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。 ——《设计模式》GoF

 为什么要使用原型模式?

我们使用原型模式是为了创建对象,在以下情况下可以考虑使用原型模式:

  • 当我们的对象类型不是一开始就确定的,而是在运行期间确定的话,那么通过利用这个对象克隆出一个新对象会更容易些。
  • 获取一个对象在某个状态下的副本
  • 处理一些较简单的对象时,且对象间的区别很小,可能就某些属性不同,就可以使用原型模式来创建新的对象。
  • 创建对象时,构造函数的参数很多,而自己不 清楚每个参数的意义,就可以使用原型模式创建对象,忽略创建的过程。

由于克隆需要一个原型,而上面的类图中Prototype就这个原型,Prototype定义了克隆自身的Clone接口,由派生类进行实现,而实现原型模式的重点就在于这个Clone接口的实现。ConcretePrototype1类和ConcretePrototype2类继承自Prototype类,并实现Clone接口,实现克隆自身的操作;同时,在ConcretePrototype1类和ConcretePrototype2类中需要重写默认的复制构造函数,供Clone函数调用,Clone就是通过在内部调用重写的复制构造函数实现的。在后续的编码过程中,如果某个类需要实现Clone功能,就只需要继承Prototype类,然后重写自己的默认复制构造函数就好了。

代码实现最简单的原型模式

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 //接口
 6 class Prototype {
 7    public:
 8     Prototype() {}
 9     virtual ~Prototype() {}
10     virtual Prototype* clone() = 0;
11 };
12 
13 //实现
14 class ConcretePrototype : public Prototype {
15    public:
16     ConcretePrototype() : mCounter(0) {}
17     virtual ~ConcretePrototype() {}
18 
19     //重写拷贝构造函数,以供clone函数调用
20     ConcretePrototype(const ConcretePrototype& rhs) { mCounter = rhs.mCounter; }
21 
22     //复制自身
23     virtual ConcretePrototype* clone() {
24         //调用拷贝构造函数
25         return new ConcretePrototype(*this);
26     }
27 
28    private:
29     int mCounter;
30 };
31 
32 int main() {
33     //生成对象
34     ConcretePrototype* conProA = new ConcretePrototype();
35 
36     //复制自身
37     ConcretePrototype* conProB = conProA->clone();
38 
39     delete conProA;
40     conProA = nullptr;
41     delete conProB;
42     conProB = nullptr;
43 
44     return 0;
45 }

与其他创建型模式的比较

工厂方法模式适用于生产较复杂,一个工厂生产单一的一种产品的时候;
抽象工厂模式适用于一个工厂生产多个相互依赖的产品;
建造者模式着重于复杂对象的一步一步创建,组装产品的过程,并在创建的过程中,可以控制每个简单对象的创建;
原型模式则更强调的是从自身复制自己,创建要给和自己一模一样的对象。

要点总结

  • 原型模式中具体的创建过程,是由对象本身提供,因此可以很方便的快速的构建新的对象。但是,原型模式的最大缺点是继承原型的子类都要实现Clone操作,这个是很困难的。例如,当所考虑的类已经存在时就难以新增Clone操作。当内部包括一些不支持拷贝或者有循环引用的对象时,实现克隆可能也会很困难。

参考:C++设计模式——原型模式

原文地址:https://www.cnblogs.com/y4247464/p/14268033.html