原型模式跟其他的创建型模式不同,它要做的是对特定的对象进行克隆。所谓克隆就是根据当前对象的特征,完全的复制一份出来。原型模式分为深拷贝和浅拷贝。不管是深拷贝和浅拷贝对于对象中的基本数据类型和String类型都会完全的复制,区别就是在复制对象中的其他引用类型时,浅拷贝只会复制对象中引用类型的地址,而不会完全的克隆一份。
浅拷贝
下面测试代码,User类中有Integer类型和String类型以及一个Father对象。User类对外提供的copy()方法使用了Object的clone()方法,就完成了对象的复制。需要注意的是,使用clone()方法的类需要实现Cloneable接口,该接口只是一个标记接口。最终的测试我们改变了克隆出来的对象的三个属性,原对象的Integer和String类型属性没有收到影响,而Father属性则收到了影响。这表明,克隆出来的对象并没有完全的复制,对于引用类型只是复制了其栈的引用。
package prototype_k;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:49
* @notify
* @version 1.0
*/
public class User implements Cloneable {
private String name;
private Integer age;
private Father father;
public User(String name, Integer age, Father father) {
this.name = name;
this.age = age;
this.father = father;
}
public User copy() throws Exception {
return (User) this.clone();
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFather(Father father) {
this.father = father;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Father getFather() {
return father;
}
}
View Code
package prototype_k;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:50
* @notify
* @version 1.0
*/
public class Father {
private String name;
public Father(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
View Code
package prototype_k;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:49
* @notify
* @version 1.0
*/
public class Main {
public static void main(String[] args) throws Exception {
User user = new User("张三", 1, new Father("张爸爸"));
User cloneUser = user.copy();
System.out.println(user == cloneUser);//false
cloneUser.setName("李四");
cloneUser.setAge(2);
Father father = cloneUser.getFather();
father.setName("李爸爸");
System.out.println(user.getName());//张三
System.out.println(user.getAge());//1
System.out.println(user.getFather().getName());//李爸爸
}
}
View Code
深拷贝
而深度拷贝需要使用对象序列化和反序列化,这个过程叫做冷冻和解冻。很好明白的,当一个对象被读取到了流里,那么流里的对象已经不是对象了,只是二进制数据,表明完全和原有的对象切断了联系。最后解冻则是一个完完全全的新的对象。需要注意的是被序列化的对象必须实现Serializable标记接口,对象内的其他引用对象也需要实现。
package prototype_k;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:49
* @notify
* @version 1.0
*/
import java.io.*;
public class User2 implements Serializable{
private String name;
private Integer age;
private Father father;
public User2(String name, Integer age, Father father) {
this.name = name;
this.age = age;
this.father = father;
}
public User2 copy() throws Exception {
ByteArrayOutputStream byteInputStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(byteInputStream);
outputStream.writeObject(this);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteInputStream.toByteArray());
ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);
Object object = inputStream.readObject();
return (User2) object;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFather(Father father) {
this.father = father;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Father getFather() {
return father;
}
}
View Code
package prototype_k;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 17:50
* @notify
* @version 1.0
*/
import java.io.Serializable;
public class Father implements Serializable {
private String name;
public Father(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
View Code
package prototype_k;/*
* @auther 顶风少年
* @mail dfsn19970313@foxmail.com
* @date 2020-01-15 18:46
* @notify
* @version 1.0
*/
public class Main2 {
public static void main(String[] args)throws Exception {
User2 user = new User2("张三", 1, new Father("张爸爸"));
User2 cloneUser = user.copy();
System.out.println(user == cloneUser);
cloneUser.setName("李四");
cloneUser.setAge(2);
Father father = cloneUser.getFather();
father.setName("李爸爸");
System.out.println(user.getName());
System.out.println(user.getAge());
System.out.println(user.getFather().getName());
}
}
View Code