原型模式

99封情书 提交于 2019-11-27 00:55:27

意图:

  用原型实例指定创建对象的种类,及复制这些原型来创造新的对象。

结构图:

 

在应用工厂模式创建对象时,需要为工厂类建立与产品类相同的继承层次,就算所有的产品都属于同一种类,相互之间只存在很小的差异,我们也不得不派生出许多工厂子类来生产这些产品。

为了减少这种子类化工作,也可以采用在创建对象时传入参数,来选择创建何种对象,但是这无疑增加了生产者和产品耦合性,使得再要增加或者修改产品种类,变得不够方便。并且,系统如何传入适当的参数以生产不同产品也存在问题。

那么,原型模式的引入,就可以解决这两方面的问题。

原型模式通过对原型实例的复制来创建新的对象,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、 对拷贝创建的对象的初始化。 

 

参考资料:

     《设计模式:可复用面向对象软件的基础》

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!