§1 定义
- 将一个已经创建好的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
§2 角色
- 抽象原型类:定义具体原型类需要实现的 clone 方法,对于 Java 来说,具体原型类直接实现 Cloneable 接口重写 clone 方法即可,无需再重新定义抽象原型类。
- 具体原型类:实现抽象原型类的 clone 方法。
- 访问类:使用具体原型类中的 clone 方法复制新对象。
§3 三好学生案例
- 班级里有多名同学获得了三好学生的奖状,除了奖状上的获奖人姓名不一样外,其他都是一样的,使用原型模式复制出多个三好学生奖状,然后修改奖状上的名字。
§3.1 浅克隆实现
§3.1.1 浅克隆定义
- 创建一个新的对象,新对象的属性和原型对象的完全相同,对于非基本类型的属性,仍然指向原型对象所指向的对象的内存地址。
§3.1.2 类图
§3.1.3 实现
public class Citation implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show() {
System.out.println("三好学生:" + name);
}
@Override
protected Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
Citation c1 = new Citation();
c1.setName("张三");
Citation c2 = c1.clone();
c2.setName("李四");
c1.show();
c2.show();
}
}
- 浅克隆模式看似一切正常,若我们把 Citation 的 name 属性改为 Student 自定义对象,再来看看会发生什么?
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Citation implements Cloneable {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public void show() {
System.out.println("三好学生:" + student.getName());
}
@Override
protected Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
Citation c1 = new Citation();
Student student1 = new Student();
student1.setName("张三");
c1.setStudent(student1);
Citation c2 = c1.clone();
Student student2 = c2.getStudent();
student2.setName("李四");
System.out.println("student1和student2是同一个对象吗?" + (student1 == student2));
c1.show();
c2.show();
}
}
- 测试结果可以看出,两个 student 对象是同一个对象,当修改克隆后的学生名字时,原型对象的名字也被修改了,这是浅克隆方式的弊端。可以使用深克隆方式解决。
§3.2 深克隆实现
§3.2.1 深克隆定义
- 创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象的地址。
§3.2.2 实现
public class Student implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Citation implements Cloneable, Serializable {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public void show() {
System.out.println("三好学生:" + student.getName());
}
@Override
protected Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
public class CitationTest {
public static void main(String[] args) throws Exception {
Citation c1 = new Citation();
Student student1 = new Student();
student1.setName("张三");
c1.setStudent(student1);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\study\\a.txt"));
oos.writeObject(c1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\study\\a.txt"));
Citation c2 = (Citation) ois.readObject();
ois.close();
Student student2 = c2.getStudent();
student2.setName("李四");
System.out.println("student1和student2是同一个对象吗?" + (student1 == student2));
c1.show();
c2.show();
}
}
- 使用序列化和反序列化的方式实现深克隆,解决浅克隆的弊端。