设计模式之原型模式与深拷贝、浅拷贝
原型模式
基本概念
使用一个已经创建的对象作为原型,通过复制该对象来创建一个新的该类型的对象。Java自带原型模式,通过实现Cloneable
接口实现,这种创建对象的方式比new
对象的效率更高。
原型模式通常用来保存对象某一过程中的状态,以实现在必要的时候撤销对对象的更改。
此方法的缺陷:
- 每一个类都需要实现
clone()
方法,而clone()
方法位于类内部,当需要对类代码进行修改时,此方法也需要修改。 - 当需要深克隆时,此类中的每一个引用类型对象都需要支持深克隆,实现较麻烦。
模式的实现
-
创建原型类,实现
Cloneable
接口,并重写clone()
方法原型类的引用类型属性
public class Member implements Cloneable{ private int age; private String name; private double length; public Member(int age, String name, double length) { this.age = age; this.name = name; this.length = length; } @Override protected Member clone() throws CloneNotSupportedException { Member res = (Member) super.clone(); return res; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getLength() { return length; } public void setLength(double length) { this.length = length; } }
原型类
public class Collection implements Cloneable { private Member member; private int id; public Collection(Member member, int id) { this.member = member; this.id = id; } @Override protected Collection clone() throws CloneNotSupportedException { Collection res = (Collection) super.clone(); //res.setMember(this.getMember().clone()); return res; } public Member getMember() { return member; } public void setMember(Member member) { this.member = member; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
-
使用该类的
clone()
方法实现克隆public class ProtoDemo { public static void main(String[] args) throws CloneNotSupportedException { Member zhangf = new Member(12, "张飞", 12.33); Collection coll = new Collection(zhangf, 1); Collection coll2 = (Collection) coll.clone(); String str1="collect01\tid="+coll.getId()+"\t"+coll.getMember()+"\tmem="+coll; String str2="collect02\tid="+coll2.getId()+"\t"+coll2.getMember()+"\tmem="+coll2; System.out.println(str1); System.out.println(str2); System.out.println("============="); coll.getMember().setName("刘备"); System.out.println("coll1`s name is "+coll.getMember().getName()); System.out.println("coll2`s name is "+coll2.getMember().getName()); } }
以上代码实现类浅拷贝,打印结果如下:
collect01 id=1 cn.sunyog.prototype.Member@e73f9ac mem=cn.sunyog.prototype.Collection@61064425
collect02 id=1 cn.sunyog.prototype.Member@e73f9ac mem=cn.sunyog.prototype.Collection@7b1d7fff
=============
coll1`s name is 刘备
coll2`s name is 刘备
可以看出,当修改了coll
对象中member
的name
属性时,coll2
对象中对应的次属性也跟着被修改了。如需要实现两个对象互不影响,需要实现深拷贝,即重写Collection
类的clone()
方法,手动修改它的所有引用类型属性。代码如下:
@Override
protected Collection clone() throws CloneNotSupportedException {
Collection res = (Collection) super.clone();
//深拷贝
res.setMember(this.getMember().clone());
return res;
}
以上代码修改后,打印结果如下:
collect01 id=1 cn.sunyog.prototype.Member@5e2de80c mem=cn.sunyog.prototype.Collection@1d44bcfa
collect02 id=1 cn.sunyog.prototype.Member@266474c2 mem=cn.sunyog.prototype.Collection@6f94fa3e
=============
coll1`s name is 刘备
coll2`s name is 张飞
可见两个对象的name
属性互不影响,实现了深拷贝