一,基本概念
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后复制这个原型对象的办法创建出更多的对象。
克隆的实现有两种:浅拷贝和深拷贝
浅拷贝:只负责克隆按值传递的数据(比如基本数据类型,String类型)
深拷贝:除了浅拷贝要克隆的值外,还负责克隆引用数据类型(属性的类型也是对象)的数据
需要注意的是执行深拷贝之后,原来的对象和新创建的对象之间不会共享任何东西,改变一个对象对另外一个不会有任何影响
具体的UML图:
客户角色(Client)角色:客户端提出创建对象的请求
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个接口或者抽象类来定义实现
具体原型(ConcretePrototype)角色:被复制的角色,此角色需要实现抽象原型角色所要求的接口
具体的代码实现:
抽象的主题角色:
具体的实现角色1:
具体的实现角色2:
在客户端中的使用:
综上,在具体的实现角色中我们都用到了clone()这个方法,注意抛出异常
二,具体应用
通过原型模式实现简历的克隆和某个部分的修改
具体的代码实现:
工作经历:
简历的原型(包含对于工作经历的引用):
注意其中对于Clone方法的实现,返回的是一个Resume类,其中通过set方法完成对于各类属性的初始化
优点:
-
想要修改某一份建立,只要修改对这份简历作一定的修改即可,不会影响到其他的简历,相同的部分就不用再重复
-
一般在初始化的信息不发生变化的情况下,克隆是最好的办法,即隐藏了创建的细节,又对性能是大大的提高
三,深拷贝与浅拷贝的具体例子
1.浅复制
被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象
抽象的接口:
具体的实现:
客户端:
在对复制之后的对象里面的值进行修改的时候,原来的对象值也会发生相应的变化
ShallowCopy对象实现了一个浅拷贝,因此当对sc1进行克隆的时候,其字段v并没有克隆,这导致sc1与sc2的字段v都指向了同一个v,因此当修改了sc1的v[0]之后,sc2的v[0]也会发生变化
2.深复制的例子:
客户端:
这个地方我们可以总结出,要是想实现深复制,就需要有一个带参的构造函数,并把它定义为私有,其中他的参数完成clone方法
然后在Clone方法的时候,返回那个带参的构造函数即可
四,原型模式的深入
-
克隆生成对象
-
如果要生成一大批很相像的类的实例时,不用每次去做重复的工作。
-
原型模式比工厂模式更为方便,灵巧,在使用的时候甚至可以达到比工厂模式更为方便灵巧的效果
原型模式如何实现工厂模式的功能?
工厂模式实现的生产产品的功能,关键是利用了继承的特性,就是说,一定是由同一个抽象产品类派生出来。所以在工厂模式下,你如果要生成一类产品,就要引入一个抽象产品类,然后再由它派生出具体的产品
同样,在原型模式中,你完全可以定义一个抽象产品--具体产品的层次,再利用具体产品本身的clone功能来产生具体产品本身,从而达到实现工厂模式的功能的目的
实际上,在原型模式中,每个具体产品就扮演了工厂模式里的具体工厂的角色(因为每个具体产品都具有生成自己拷贝的功能,从这种意义上讲,这正是工厂的作用)
总结:
Prototype模式通过复制原型而获得新对象创建的功能,这里Prototyoe本身就是“对象工厂”(因为他本身就可以产生对象)
原型模式从自身复制自己创建新对象
优点:
原型模式允许动态的增加或减少产品类。由于创建产品类实例的方法是产品类内部具有的,因此增减新产品对于整个结构没有影响
原型模式提供了简化了的创建结构,工厂方法模式常常需要有一个与产品等级结构相同的等级结构,而原型模式不需要这样
缺点:
最主要的缺点是每一个类型的子类都必须实现clone操作,尤其包含引用类型的对象的时候,clone方法会比较麻烦,必要时能够递归地让所有的相关对象都要正确的实现克隆
五,原型模式的扩展
分析:因为1000份订单都是相同的,所以使用克隆方法模式就可以,然后需要有两个具体的克隆类,实现客户订单和公司订单
抽象主题:
公司订单:
这个类中不含有对其他类的引用,所以就不需要再建立一个带参的构造函数
直接在Clone方法中建立即可
这样写也是有一些缺陷的,我们可以考虑把产品类具体实现,然后在个人订单和公司订单里加以引用,
如果把产品编号和名称直接在订单中定义,这样就增加了耦合性,导致我们在创建不同的产品的类的时候需要在创建一个新的订单