设计模式之原型模式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之原型模式相关的知识,希望对你有一定的参考价值。
原型模式是一种创建型设计模式,它允许一个对象再创建另一个可定制的对象,根本无需知道任何创建的细节。
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
问题描述:创建一个重复的结构复杂的对象时的成本比较大,比如细胞分裂、新建一个模板等。
解决方案:将这个结构复杂的对象作为一个原型,然后通过复制这个原型对象来创建更多同类型的对象。
结构图:
说明:
(1)抽象原型类(Cloneable):这是一个抽象角色,可用接口或抽象类来实现,这里声明了一个克隆的方法,是所有具体原型类共同拥有的父类或接口;
(2)具体原型类:继承或实现抽象原型类的克隆方法,返回自己的一个克隆对象;
(3)使用者(User):让一个已有的原型对象通过调用其克隆方法,获得该对象的克隆对象。
举个栗子:讲一个孙悟空拔毛变小猴儿的故事,将孙悟空作为一个原型对象,克隆出不同的小猴儿,使用原型模式来实现。
1. 新建一个原型类MonkeyPrototype,实现Cloneable接口中的clone()方法,返回自己的一个克隆对象,其中引用了Address对象。代码如下:
2. 在类PrototypeFragment中使用一个已有的原型对象,通过调用其克隆方法获得该对象的克隆对象,并对克隆对象的名字name和地址address进行更改。代码如下:
4. 运行后的效果,如图所示:
上面的实现方式叫作浅克隆,它只能克隆对象本身,对于依附于对象的对象则不予克隆,只对其地址克隆。栗子中,Address就是依附于原型类MonkeyPrototype的对象的对象,只克隆了它的引用地址,当克隆对象monkey_A对地址做出改动时,比如将“花果山”改为“峨眉山”,原型对象和克隆对象的地址都发生了改变。也就是说,如果原型对象的成员变量是值类型,则进行复制,不会互相影响;如果是引用类型,比如Address,则将其地址复制,实质上指向的是同一个对象。
浅克隆需要注意的地方:
(1)被克隆的对象需要实现需要实现Cloneable;
(2)要重写clone() 方法;
(3)对于依附于被克隆对象的对象,只克隆其地址。一旦更改都会改变。
下面用深克隆来实现原型模式。具体实现方式如下:
1. 让原型类MonkeyPrototype实现可序列化接口Serializable,增加一个deepClone()方法。代码如下:
2. 在类PrototypeFragment中仍然使用这个已有的原型对象,通过调用deepClone()方法对该对象的进行深克隆,并对克隆对象的名字name和地址address进行更改。代码如下:
3. 运行后的效果,如图所示:
由上可知,深克隆利用了IO流进行存储,然后进行读取,不仅对克隆对象进行克隆,而且对其依附着的对象也进行了克隆。如栗子所示,原型猴儿携带的信息包含孙悟空、六耳猕猴和峨眉山,深克隆后的对象是猴儿B,我更改了名字和地址,其中名字name是值类型成员变量,则复制后改变不会影响原型对象的值,地址address是引用类型成员变量,因为是深克隆,所以也复制了一份给克隆对象,所以更改后也将不会影响到原型对象中的地址值。
深克隆,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象。
深克隆需要注意的地方:
(1)利用IO流进行存储,然后进行读取;
(2)需要实现可序列化接口Serializable。
优点:
(1)当创建一个结构复杂的对象时,原型模式可以简化其创建过程,通过复制已有的实例来获得相同的对象;
(2)简化创建结构,不需要专门的工厂存在,仅需要实现克隆方法即可。
缺点:
(1)必须实现Cloneable接口;
(2)逃避构造函数的约束;
(3)克隆方法在类的内部,加重类的职责,当需要对已有类进行改造时需要修改原型类。
使用场景:
(1)当创建成本比较大的时候,新的对象可以使用原型模式来获得;
(2)系统要保存对象的状态,并且对象本身占用内存很少,比如要恢复到某个时间的某种状态,可以使用原型模式配合备忘录模式来实现。
以上是关于设计模式之原型模式的主要内容,如果未能解决你的问题,请参考以下文章