原型模式问题引出:
现在有一个羊对象,现在需要设计程序将这只羊克隆,即创建相同的对象。常见的思路是重复执行new操作,缺点也是显而易见的,每次创建新的对象时,都要获取原对象的属性传入到构造器中,效率较低,使用原型模式可以解决这个问题。
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
原型模式的角色及职责:
1)Prototype:原型类,声明一个克隆自己的接口
2)ConcretePrototype:具体的原型类,实现一个克隆自己的操作
3)Client:让一个原型对象克隆自己,从而创建一个新的对象
克隆羊例子
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private Sheep friend;
public Sheep(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
@Override
protected Object clone() {
Sheep sheep=null;
try {
sheep= (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
}
客户端调用:
public class Client {
public static void main(String[] args) {
Sheep sheep=new Sheep("tom",1,"白色");
sheep.setFriend(new Sheep("Jack",2,"黑色"));
Sheep sheep1= (Sheep) sheep.clone();
Sheep sheep2= (Sheep) sheep.clone();
System.out.println("sheep:"+sheep+" hashcode="+sheep.getFriend().hashCode());
System.out.println("sheep1:"+sheep1+" hashcode="+sheep1.getFriend().hashCode());
System.out.println("sheep2:"+sheep2+" hashcode="+sheep2.getFriend().hashCode());
}
}
可见3个对象引用变量的hashcode都一样,因此是浅拷贝:
浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对直接引用进行拷贝,没有对直接引用指向的对象进行拷贝。这种情况下一个对象改变成员变量会影响到另一个对象的成员变量。
深拷贝是指为所有引用数据类型的成员变量都申请存储空间,并复制每个引用数据类型成员变量所引用的对象,也就是说对象进行深拷贝要对所有对象进行拷贝。
深拷贝实现方式1:重写clone实现深拷贝
深拷贝实现方式2:通过对象序列化实现深拷贝
例子
原型类
public class DeepPrototype implements Serializable,Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
//重写clone实现深拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep=null;
//这里完成基本数据类型和String的克隆
deep=super.clone();
//对引用类型的属性进行单独处理
DeepPrototype deepPrototype= (DeepPrototype) deep;
deepPrototype.deepCloneableTarget= (DeepCloneableTarget) deepCloneableTarget.clone();
return deepPrototype;
}
//使用对象的序列化实现深拷贝
public Object deepClone() throws IOException {
ByteArrayOutputStream byteArrayOutputStream=null;
ObjectOutputStream objectOutputStream = null ;
ByteArrayInputStream byteArrayInputStream=null;
ObjectInputStream objectInputStream=null;
try {
//序列化
byteArrayOutputStream=new ByteArrayOutputStream();
objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
//反序列化
byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
objectInputStream=new ObjectInputStream(byteArrayInputStream);
DeepPrototype deepPrototype= (DeepPrototype) objectInputStream.readObject();
return deepPrototype;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}finally {
byteArrayOutputStream.close();
byteArrayInputStream.close();
objectInputStream.close();
objectOutputStream.close();
}
}
}
原型类中引用类型成员变量的类
public class DeepCloneableTarget implements Serializable,Cloneable {
private static final long serialVersionUID=1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
客户端调用
public class Client {
public static void main(String[] args) throws CloneNotSupportedException, IOException {
DeepPrototype p=new DeepPrototype();
p.name="小羊";
p.deepCloneableTarget=new DeepCloneableTarget("小羊","小羊的类");
DeepPrototype p1= (DeepPrototype) p.clone();
DeepPrototype p2= (DeepPrototype) p.deepClone();
System.out.println("p.name="+p.name+" p.deepCloneableTarget="+p.deepCloneableTarget.hashCode());
System.out.println("p1.name="+p1.name+" p1.deepCloneableTarget="+p1.deepCloneableTarget.hashCode());
System.out.println("p2.name="+p1.name+" p2.deepCloneableTarget="+p2.deepCloneableTarget.hashCode());
}
}
结果
各对象的引用变量的hashcode不一样,可见实现了深拷贝