意图:
用原型实例指定创建对象的种类,及复制这些原型来创造新的对象。
结构图:
在应用工厂模式创建对象时,需要为工厂类建立与产品类相同的继承层次,就算所有的产品都属于同一种类,相互之间只存在很小的差异,我们也不得不派生出许多工厂子类来生产这些产品。
为了减少这种子类化工作,也可以采用在创建对象时传入参数,来选择创建何种对象,但是这无疑增加了生产者和产品耦合性,使得再要增加或者修改产品种类,变得不够方便。并且,系统如何传入适当的参数以生产不同产品也存在问题。
那么,原型模式的引入,就可以解决这两方面的问题。
原型模式通过对原型实例的复制来创建新的对象,Prototype类,为一个抽象类,用以定义一个抽象接口Clone()方法,该方法由具体的派生类实现:
class Prototype{
public :
virtual Prototype* Clone();
}
派生类实现Clone接口:
class ConcretePrototype1: public Prototype{
public:
ConcretePrototype1* Clone(){return copy of self}
}
ConcretePrototype1* cnrtProtyp1 = new ConcretePrototype1();
系统中,通过对实例化的Prototype对象调用Clone函数,来创建新的对象:
Prototype * p = cnrtProtyp1->Clone();
借由这种复制来创建对象的方式,从结构图可以看出,生产对象的Client部分,无需对应右边的Prototype的每一个具体对象类派生出相应的层次,如对应ConcretePrototype1的ConcretePrototype1Factory类,也没有采用在创建对象时,传递参数的方法:
CreateObject(typeParameter){
swich(typeParameter){
case 1:
return new ConcretePrototype1;break;
case 2:
return new ConcretePrototype2;break;
......
}
}
如上采用硬编码的方式来在编译时确定应该生产对象类型的方法,无疑降低了创建对象的灵活性和复用性。
通过使用原型模式可以得到的另一个好处是,在运行时可以通过注册和注销的形式将新的产品类引进或撤出系统。举例而言,在采用动态加载技术的程序中,动态的加载到程序中的类,无法在程序运行前的获知具体类型,因此无法创建新的对象。而通过加载到程序里的类型实例对象,将其注册到原型管理器中,即可方便的将该类型引入系统,并可方便的再由复制来新建该类型的对象。
而对Clone函数的实现,需要注意的是“深拷贝”和“浅拷贝”的问题:当我们在执行复制操作时,返回的是原对象实例的复本,还是仅仅只是和原变量进行了共享。在Prototype结构比较复杂时通常要求进行的是深拷贝,需要由你来决定哪些成员是可以共享的(尤其是当类存在指针成员的时候);
适用性:
1、 当类的实例化是在运行时,比如动态加载,确定的,
2、 避免建立与产品同样继承层次的工厂类,
3、 类与类的实例之间差异较小,通过复制一个实例再修改属性更加方便时
实现要点:
1、 使用原型管理器,可以方便的对系统进行扩展;
2、 Clone操作的实现,注意深、浅拷贝的不同,以及实现时机和方法;
3、 对拷贝创建的对象的初始化。
参考资料:
《设计模式:可复用面向对象软件的基础》
来源:http://www.cnblogs.com/CS106A/archive/2012/06/07/2539102.html