原型模式分析
原型模式(PrototypePattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
.
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
原型模式分为:
- 浅克隆
- 深克隆
浅克隆
只负责克隆按值传递的数据(比如基本数据类型、String类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。
也就是说如果被克隆的对象中,有对其他对象的引用,那么就只复制那个对象的引用,而不是重新复制一个新的对象。
看下代码示例
public class AdjectiveCopy {
static class Protro implements Cloneable{
private String aa = "aaaa";
private ProtroVar protroVar = new ProtroVar();
@Override
protected Protro clone() {
Protro protro = null;
try {
protro = (Protro) super.clone();
} catch (CloneNotSupportedException e){
e.printStackTrace();
}
return protro;
}
}
static class ProtroVar {
private String bb = "bbb";
}
public static void main(String[] args){
Protro protro = new Protro();
Protro clonePro = protro.clone();
System.out.println("hashCode: "+(protro.hashCode() == clonePro.hashCode()));
System.out.println("proVar: "+(protro.protroVar.hashCode() == clonePro.protroVar.hashCode()));
}
}
打印结果:
hashCode: false
proVar: true
深克隆
除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。
深克隆的方法有,反序列化,重写Clone()方法等。
public class DeepCopy {
static class Protro implements Serializable{
private String aadd = "aadd";
private ProtroBB protrobb = new ProtroBB();
public Protro() {
}
public Object deepClone() {
Object o = null;
try {
//将对象写到流里
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
//从流里读出来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
o = oi.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return o;
}
}
static class ProtroBB implements Serializable {
private String cc = "cc";
}
public static void main(String[] args){
Protro protro = new Protro();
Protro clonePro = (Protro) protro.deepClone();
System.out.println("hashCode: "+(protro.hashCode() == clonePro.hashCode()));
System.out.println("proVar: "+(protro.protrobb.hashCode() == clonePro.protrobb.hashCode()));
}
}
打印结果
hashCode: false
proVar: false
优点:
- 向客户隐藏制造新实例的复杂性。
- 提供让客户能够产生未知类型对象的选项。
- 在某些环境下,复制对象比创建对象更加有效。
缺点:
- 对象的复制有时相当的复杂。特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。
用途:
- 在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型