您的位置:首页 > 其它

设计模式 - 原型模式

2015-11-30 13:16 615 查看
原型模式是创建型模式的一种,其特点在于通过 “复制” 一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的 “原型”,这个原型是可定制的。

类图



代码实现

用于测试的 JavaBean:

package com.huey.pattern.prototype;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@ToString
@NoArgsConstructor
@AllArgsConstructor
public class TestBean implements Serializable {

/**
*
*/
private static final long serialVersionUID = -2351683706932774662L;

@Getter @Setter
private String testValue;

}


抽象原型:

package com.huey.pattern.prototype;

/**
* the abstract prototype
* @author  huey
* @version 1.0
* @created 2015-11-27
*/
public abstract class Prototype implements Cloneable {

public Prototype() {
System.out.println("Prototype is constructed.");
}

@Override
protected Prototype clone() {
try {
return (Prototype) super.clone();
} catch (Exception e) {
return null;
}
}

}


具体原型:

package com.huey.pattern.prototype;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
* the concrete prototype
* @author  huey
* @version 1.0
* @created 2015-11-27
*/
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ShallowCopyBean extends Prototype {

@Getter @Setter
private Integer primitiveValue;
@Getter @Setter
private TestBean customValue;

}


单元测试:

package com.huey.pattern.prototype;

public class ShallowCopyBeanTest {

public static void main(String[] args) {
Prototype cloneableBean = new ShallowCopyBean(10, new TestBean("AAA"));
System.out.println("cloneableBean: " + cloneableBean);

ShallowCopyBean clonedBean = (ShallowCopyBean) cloneableBean.clone();
clonedBean.setPrimitiveValue(100);
clonedBean.getCustomValue().setTestValue("BBB");
System.out.println("cloneableBean: " + cloneableBean);
System.out.println("clonedBean: " + clonedBean);
}

}


结果输出:

Prototype is constructed.
cloneableBean: ShallowCopyBean(primitiveValue=10, customValue=TestBean(testValue=AAA))
cloneableBean: ShallowCopyBean(primitiveValue=10, customValue=TestBean(testValue=BBB))
clonedBean: ShallowCopyBean(primitiveValue=100, customValue=TestBean(testValue=BBB))


从输出可以看到,原型只被构造一次。但是这里需要注意当 clonedBean 的引用对象 customVaule 的内容发生改变时,cloneableBean 的 customVaule 也跟着改变。这就是深拷贝与浅拷贝的问题,Java 中,Object 类的 clone 方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

深拷贝

实现深拷贝可以在重写 clone 方法中,对数组、容器对象、引用对象等自己进行拷贝。

还可以使用一个技巧,就是利用序列化的机制来实现,通过将对象序列化到输出流中,然后将其读回,这样产生的新对象是对现有对象的一个深拷贝。

代码实现

可序列化的抽象原型:

package com.huey.pattern.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
* the abstract prototype
* @author  huey
* @version 1.0
* @created 2015-11-27
*/
public abstract class SerialCloneable implements Serializable, Cloneable {

/**
*
*/
private static final long serialVersionUID = -2477239830471073680L;

@Override
protected Object clone() {
try {
/**
* serialize the object to the output stream
*/
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream output = new ObjectOutputStream(bout);
output.writeObject(this);
output.close();

/**
* deserialize the object from the input stream
*/
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream input = new ObjectInputStream(bin);
Object result = input.readObject();
input.close();

return result;
} catch (Exception e) {
return null;
}
}
}


具体原型:

package com.huey.pattern.prototype;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
* the concrete prototype
* @author  huey
* @version 1.0
* @created 2015-11-27
*/
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class DeepCopyBean extends SerialCloneable {

/**
*
*/
private static final long serialVersionUID = -959424582381713341L;

@Getter @Setter
private Integer primitiveValue;
@Getter @Setter
private TestBean customValue;

}


单元测试:

package com.huey.pattern.prototype;

public class DeepCopyBeanTest {

public static void main(String[] args) {

SerialCloneable cloneableBean = new DeepCopyBean(10, new TestBean("AAA"));
System.out.println("cloneableBean: " + cloneableBean);

DeepCopyBean clonedBean = (DeepCopyBean) cloneableBean.clone();
clonedBean.setPrimitiveValue(100);
clonedBean.getCustomValue().setTestValue("BBB");
System.out.println("cloneableBean: " + cloneableBean);
System.out.println("clonedBean: " + clonedBean);
}

}


结果输出:

cloneableBean: DeepCopyBean(primitiveValue=10, customValue=TestBean(testValue=AAA))
cloneableBean: DeepCopyBean(primitiveValue=10, customValue=TestBean(testValue=AAA))
clonedBean: DeepCopyBean(primitiveValue=100, customValue=TestBean(testValue=BBB))


从输出可以看到,clonedBean 的引用对象 customVaule 的内容发生改变时,不会影响到 cloneableBean 的 customVaule。

原型模式的适用场合

1) 产生对象过程比较复杂,初始化需要许多资源时;

2) 希望框架原型和产生对象分开时;

3) 同一个对象可能会供其他调用者使用访问时。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: