原型模式
用一个已经创建的对象作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
原型模式包含如下角色:
- 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
类图
原型模式的克隆分为浅克隆和深克隆。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
浅克隆案例
用浅克隆生成学生奖状
类图
奖状类代码
/**
* @author Watching
* * @date 2023/3/16
* * Describe:
*/
public class Citations implements Cloneable {
public Citations() {
System.out.println("执行构造方法");
}
private Student student = new Student();
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
@Override
protected Citations clone() throws CloneNotSupportedException {
System.out.println("执行克隆方法");
return (Citations) super.clone();
}
}
Student为一个引用类型的成员变量
测试类代码
/**
* @author Watching
* * @date 2023/3/16
* * Describe:
* 浅克隆是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象
* 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Citations citations = new Citations();
Citations clone = citations.clone();
//浅克隆是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象
System.out.println(citations == clone);//结果为false
System.out.println(citations.getStudent() == clone.getStudent());//结果为true
citations.getStudent().setName("张三");
clone.getStudent().setName("李四");
System.out.println(citations.getStudent().getName());
//结果是李四,说明clone对象修改Student类型的变量导致citations中的变量修改了。
//说明两个对象的Student引用都是指向的同一个地址
}
}
根据结果可以得出结论,实现Cloneable接口使用clone()方法生成的对象是浅拷贝。
深克隆案例
这里我们使用对象流序列化来实现深克隆,我们在破坏单例模式中也使用过对象流序列化
奖状类代码
奖状类代码基本不变,唯一不同的就是不需要实现Cloneable接口了,因为我们这个案例不需要使用clone()方法来克隆对象。并且需要实现一个Serializable接口,因为需要序列化。而且Cations奖状类中的引用成员变量也需要实现Serializable接口,它也需要序列化
/**
* @author Watching
* * @date 2023/3/16
* * Describe:
*/
public class Citations implements Serializable {
public Citations() {
System.out.println("执行构造方法");
}
private Student student = new Student();
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
测试类代码
测试类代码需要做一些改变,使用序列化代替clone。
/**
* @author Watching
* * @date 2023/3/16
* * Describe:
* 深克隆:创建一个新对象,属性中引|用的其他对象也会被克隆,不再指向原有对象地址。
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Citations citations = new Citations();
//使用序列化深拷贝一个Citations对象出来,想要使用序列化,必须保证该类及其引用类型成员实现Serializable接口
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\d.txt")));
oos.writeObject(citations);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\d.txt")));
Citations citations1 = (Citations) ois.readObject();
citations.getStudent().setName("张三");
citations1.getStudent().setName("李四");
System.out.println(citations.getStudent().getName());//结果是张三
//说明修改citations1中的Student类型成员变量并没有影响到citation中的成员变量
}
}
根据结果可以得出结论,序列化是可以得到一个“完全崭新的对象的”(深拷贝)
重点
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。