设计模式记录(2.4)
第十二章 原始模型模式
原始模型模式属于对象的创建模式。通过给出一个原型对象来指明所要创建的对象模型,然后用复制这个原型对象的办法创建出更多同类型的对象。这就是原始模型模式的用意。
java对象的复制
java.lang.Object.clone()方法
java的所有类都是从java.lang.Object类继承而来的,而Object类提供下面的方法对对象进行复制:
protected Object clone()
子类当然可以把这个方法置换掉,提供满足自己的复制方法。对象的复制有一个基本问题,就是对象通常都有对其他的对象的引用。当使用Object类的clone()方法来复制一个对象时,此对象对其他对象的引用也同时会被复制一份。
java语言提供的Cloneable接口只起一个作用,就是在运行时期通知java虚拟机可以安全地在这个类上使用clone方法。通过调用这个clone方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类没有实现Cloneable接口时,调用clone方法会抛出CloneNotSupportException异常。
代码如下:
在运行时,客户端首先创建了一个PandaToClone的实例,并且给各个性质赋值。然后将此对象复制一份。
克隆满足的条件:
clone()方法将对象复制了一份并返还给调用者,所谓“复制”的含义与clone()方法是怎么实现的有关。一般而言,clone()方法满足以下的描述:
1.对任何的对象x,都有:x.clone()!=x。换言之,克隆对象与原对象不是同一个对象。
2.对任何的对象x,都有x.clone().getClass == x.getClass(),换言之,克隆对象与原对象的类型一样。
3.如果对象x的equals()方法定义恰当的话,那么x.clone().equals(x)应当是成立的。
在java语言的API中,凡是提供了clone()方法的类,都满足上面的这些条件。java言语的设计师在设计自己的clone()方法时,也应当遵守这三个条件。
一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的。本书希望遵守所有的三条。
equals()方法的讨论
下面给出java.lang.Object的源代码:
实现代码如下:
客户端:
示意性代码如下:
抽象原型角色Prototype源代码:
Monkey类:package com.javapatterns.prototype.monkeyking2;import java.util.Date;import java.io.Serializable;public class GoldRingedStaff implements Cloneable, Serializable{ private float height = 100.0F; private float diameter = 10.0F; public GoldRingedStaff() { //write your code here } public void grow() { this.diameter *= 2.0; this.height *= 2; } public void shrink() { this.diameter /= 2; this.height /= 2; } public void move() { //write your code for moving the staff } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } public float getDiameter() { return diameter; } public void setDiameter(float diameter) { this.diameter = diameter; } }
为做到深复制,所有需要复制的对象都需要事先java.io.Serializable接口。这表明此类可以被安全地复制。
从运行结果可以看出,大圣的金箍棒和他的身外之身的金箍棒不是同一个对象,这是因为使用了深复制,从而把大圣本尊所引用的对象也都复制了一遍,其中也包括金箍棒。
什么时候使用原型模式
对于产品结构可能会有经常性变化的系统来说,采用工厂模式就有不方便之处。这时如果采取原始模型模式,给每一个产品类配备一个克隆方法(通常情况下只需给产品类登记结构的根类配备一个克隆方法),便可以避免使用工厂模式所带来的具有等级结构的工厂类。
这样,一个使用了原始模型模式的系统与它的产品对象是怎么创建出来的,以及这些产品对象之间的结构式怎样的,以及这个结构会不会发生变化是没有关系的。
原始模型的优点:
1.原始模型模式允许动态地增加或减少产品类。由于创建产品类实例的方法是产品类内部具有的,因此,增加新产品对整个结构没有影响。
2.原始模型模式提供简化的创建结构。java语法本身就支持。
3.具有给一个应用软件动态加载新功能的能力。如果系统的某个部分不再符合原有的要求,那么只要提供一个这个类的克隆,并在客户端登记即可,没有必要再给软件用户一个新的软件包。
4.产品类不需要非得有任何事先确定的等级结构,因为原始模型模式适用于任何等级结构。
原始模型模式最主要的缺点:
是每一个类都必须配备一个克隆方法。配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类来说不是很难,而对于已经有的类不一定能很容易,特别是当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。