原型模式
§1 定义 §2 角色 §3 三好学生案例 §3.1 浅克隆实现 §3.1.1 浅克隆定义 §3.1.2 类图 §3.1.3 实现
§3.2 深克隆实现
§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 ( ) ;
}
}
使用序列化和反序列化 的方式实现深克隆,解决浅克隆的弊端。