学习设计模式之原型模式
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
结构图
- Prototype:原型类,声明一个克隆自身的接口
- ConcretePrototype:具体原型类,实现一个克隆自身的操作
- Client:客户端,让一个原型克隆自身从而创建一个新的对象
代码实现
public class PrototypeA01 implements Cloneable {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "PrototypeA01{" +
"id=" + id +
'}';
}
}
public class TestMain {
public static void main(String[] args) throws CloneNotSupportedException {
PrototypeA p = new PrototypeA();
p.setId(1);
System.out.println(p);
PrototypeA clonep = (PrototypeA) p.clone();
System.out.println(clonep);
}
}
运行结果
PrototypeA{id=‘1’}
PrototypeA{id=‘1’}
Process finished with exit code 0
关键点在于,实现 Cloneable 接口以及用 object 的 clone 方法。这样就可以不用实例化对象,直接克隆就可以了,只需要实现这个接口就可以完成原型模式了!
浅克隆与深克隆
在原型模式中有两个概念我们需要了解一下,就是浅克隆和深克隆的概念。如果对象里的属性都是值类型那么没有问题,如果对象里有引用类型则是复制引用而不是复制引用的对象,因此原始对象及其复制对象引用同一个对象。
浅克隆
深克隆
例如
public class PrototypeA01 implements Cloneable {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "PrototypeA01{" +
"id=" + id +
'}';
}
}
public class PrototypeA01 {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "PrototypeA01{" +
"id=" + id +
'}';
}
}
public class TestMain {
public static void main(String[] args) throws CloneNotSupportedException {
PrototypeA p = new PrototypeA();
PrototypeA01 pa01 = new PrototypeA01();
pa01.setId(2);
p.setId(1);
p.setPrototypeA01(pa01);
System.out.println(p);
PrototypeA clonep = (PrototypeA) p.clone();
System.out.println(clonep);
// 现在来修改这个对象
pa01.setId(3);
System.out.println(p);
System.out.println(clonep);
}
}
运行结果
PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
PrototypeA{id=1, prototypeA01=PrototypeA01{id=3}}
PrototypeA{id=1, prototypeA01=PrototypeA01{id=3}}
Process finished with exit code 0
从运行结果来看原始对象和克隆对象的属性都改变了。深克隆,我就不用多说了吧,就是什么都是单独的!全部复制,然后各自独立。你修改克隆对象对于原型对象没有丝毫影响。
代码实现之需要在对应的属性类上再次实现 Cloneable 接口以及用 object 的 clone 方法就可以了。
public class PrototypeA implements Cloneable {
private int id;
private PrototypeA01 prototypeA01;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public PrototypeA01 getPrototypeA01() {
return prototypeA01;
}
public void setPrototypeA01(PrototypeA01 prototypeA01) {
this.prototypeA01 = prototypeA01;
}
@Override
protected Object clone() throws CloneNotSupportedException {
PrototypeA clone = (PrototypeA) super.clone();
clone.setPrototypeA01((PrototypeA01) getPrototypeA01().clone());
return clone;
}
@Override
public String toString() {
return "PrototypeA{" +
"id=" + id +
", prototypeA01=" + prototypeA01 +
'}';
}
}
public class PrototypeA01 implements Cloneable {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "PrototypeA01{" +
"id=" + id +
'}';
}
}
public class TestMain {
public static void main(String[] args) throws CloneNotSupportedException {
PrototypeA p = new PrototypeA();
PrototypeA01 pa01 = new PrototypeA01();
pa01.setId(2);
p.setId(1);
p.setPrototypeA01(pa01);
System.out.println(p);
PrototypeA clonep = (PrototypeA) p.clone();
System.out.println(clonep);
// 现在来修改这个对象
pa01.setId(3);
System.out.println(p);
System.out.println(clonep);
}
}
运行结果
PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
PrototypeA{id=1, prototypeA01=PrototypeA01{id=3}}
PrototypeA{id=1, prototypeA01=PrototypeA01{id=2}}
Process finished with exit code 0
从结果来看都是单独的!全部复制,然后各自独立。
总结
原型模式的Prototype类必须继承Cloneable接口,并对接口中的clone方法进行实现。
优点
使用原型模型创建一个对象比直接new一个对象更有效率,因为它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
缺点
在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。