一、概念与通用格式
本章借鉴了《大话设计模式》之外,也借鉴了这篇博客https://www.cnblogs.com/lfxiao/p/6812835.html
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型 创建新的对象。
这相当于是对一个对象“复制黏贴”,新的对象有自己的引用地址。
当对象创建比较复杂时,可使用原型模式。
如图:
注意:clone()里return不能return this;这样就相当于把原来的对象地址传过来,return的还是原来的对象,不是新的引用地址。
当每次new一个对象,都需要执行一次构造函数,如果构造函数执行的时间很长,那么多次操作就降低了效率。一般在初始化的信息不发生变化的情况下,克隆是很好的办法,既隐藏了对象创建的细节,又提高了性能。
二、java提供的接口
当然,像这样常用的模式,java一定给了相应的接口 Cloneable。
Java语言提供的clone():
package cn.sasa.prototypeTest; public class ConcretePrototype2 implements Cloneable{ private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public Object clone() { Object cloneObj = null; try { cloneObj = super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return cloneObj; } }
三、浅复制与深复制
假设 我们再加一个类Pet,作为ConcretePrototype2的一个成员
package cn.sasa.prototypeTest; import java.io.Serializable; public class Pet implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String petName; public String getPetName() { return petName; } public void setPetName(String petName) { this.petName = petName; } }
客户端测试:
我们发现,复制的新的对象和原来的是不一样的内存地址,但是对象里的引用类型的成员,clone过来的是原对象的内存地址,这就是浅复制。
即浅复制是:如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用,但不复制引用的对象。
由于浅复制的引用类型成员引用的同一地址,如果更改其中一个,原模板对象也随之改变。
深复制是和浅复制相对的,这里引用这篇博客的截图,https://www.cnblogs.com/lfxiao/p/6812835.html
所以代码修改如下:
package cn.sasa.prototypeTest; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class ConcretePrototype2 implements Cloneable,Serializable{ private static final long serialVersionUID = 1L; private int id; private String name; private Pet pet; public ConcretePrototype2() { pet = new Pet(); } public Pet getPet() { return pet; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void SetPetName(String petName) { this.pet.setPetName(petName); } public Object clone() { Object cloneObj = null; try { cloneObj = super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return cloneObj; } public ConcretePrototype2 deepClone() throws IOException, ClassNotFoundException { //将对象写入流中 ByteArrayOutputStream bao=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bao); oos.writeObject(this); //将对象从流中取出 ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray()); ObjectInputStream ois=new ObjectInputStream(bis); return (ConcretePrototype2)ois.readObject(); } }
测试: