文章目錄
- 一、原型模式
- 1. 概述
- 2. 結構
- 3. 實現
- 4. 案例
- 1.5 使用場景
- 1.6 擴展(深克隆)
一、原型模式
1. 概述
用一個已經創建的實例作為原型,通過復制該原型對象來創建一個和原型對象相同的新對象。
2. 結構
原型模式包含如下角色:
- 抽象原型類:規定了具體原型對象必須實現的 clone() 方法。
- 具體原型類:實現抽象原型類的 clone() 方法,它是可被復制的對象。
- 訪問類:使用具體原型類中的 clone() 方法來復制新的對象。
接口類圖如下:
3. 實現
原型模式的克隆分為淺克隆和深克隆。
淺克隆:創建一個新對象,新對象的屬性和原來對象完全相同,對于非基本類型屬性,仍指向原有屬性所指向的對象的內存地址。
深克隆:創建一個新對象,屬性中引用的其他對象也會被克隆,不再指向原有對象地址。
Java中的Object類中提供了
clone()
方法來實現淺克隆。 Cloneable 接口是上面的類圖中的抽象原型類,而實現了Cloneable接口的子實現類就是具體的原型類。
Realizetype(具體的原型類):
public class Realizetype implements Cloneable {public Realizetype() {System.out.println("具體的原型對象創建完成!");}@Overridepublic Realizetype clone() throws CloneNotSupportedException {System.out.println("具體原型復制成功!");return (Realizetype) super.clone();}
}
PrototypeTest(測試訪問類):
public class PrototypeTest {public static void main(String[] args) throws CloneNotSupportedException {//創建一個原型類對象Realizetype realizetype = new Realizetype();//調用Realizetype類中的clone方法進行對象的克隆Realizetype clone = realizetype.clone();System.out.println("原型對象和克隆出來的是否是同一個對象?" + (realizetype == clone));}
}
運行結果為:
4. 案例
用原型模式生成“三好學生”獎狀
同一學校的“三好學生”獎狀除了獲獎人姓名不同,其他都相同,可以使用原型模式復制多個“三好學生”獎狀出來,然后在修改獎狀上的名字即可。
獎狀類:
public class Citation implements Cloneable {private String name;public void setName(String name) {this.name = name;}public String getName() {return (this.name);}public void show() {System.out.println(name + "同學:在2020學年第一學期中表現優秀,被評為三好學生。特發此狀!");}@Overridepublic 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();}
}
運行結果為:
1.5 使用場景
- 對象的創建非常復雜,可以使用原型模式快捷的創建對象。
- 性能和安全要求比較高。
1.6 擴展(深克隆)
將上面的“三好學生”獎狀的案例中Citation類的name屬性修改為Student類型的屬性。
獎狀類:
public class Citation implements Cloneable {private Student stu;public Student getStu() {return stu;}public void setStu(Student stu) {this.stu = stu;}void show() {System.out.println(stu.getName() + "同學:在2020學年第一學期中表現優秀,被評為三好學生。特發此狀!");}@Overridepublic Citation clone() throws CloneNotSupportedException {return (Citation) super.clone();}
}
學生類:
public class Student {private String name;private String address;public Student(String name, String address) {this.name = name;this.address = address;}public Student() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
}
測試類:
public class CitationTest {public static void main(String[] args) throws CloneNotSupportedException {Citation c1 = new Citation();Student stu = new Student("張三", "西安");c1.setStu(stu);//復制獎狀Citation c2 = c1.clone();//獲取c2獎狀所屬學生對象Student stu1 = c2.getStu();stu1.setName("李四");//判斷stu對象和stu1對象是否是同一個對象System.out.println("stu和stu1是同一個對象?" + (stu == stu1));c1.show();c2.show();}
}
運行結果為:
說明:
? stu對象和stu1對象是同一個對象,就會產生將stu1對象中name屬性值改為“李四”,兩個Citation(獎狀)對象中顯示的都是李四。這就是淺克隆的效果,對具體原型類(Citation)中的引用類型的屬性進行引用的復制。這種情況需要使用深克隆,而進行深克隆需要使用對象流。
public class CitationTest1 {public static void main(String[] args) throws Exception {Citation c1 = new Citation();Student stu = new Student("張三", "西安");c1.setStu(stu);//創建對象輸出流對象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));//將c1對象寫出到文件中oos.writeObject(c1);oos.close();//創建對象出入流對象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));//讀取對象Citation c2 = (Citation) ois.readObject();//獲取c2獎狀所屬學生對象Student stu1 = c2.getStu();stu1.setName("李四");//判斷stu對象和stu1對象是否是同一個對象System.out.println("stu和stu1是同一個對象?" + (stu == stu1));c1.show();c2.show();}
}
運行結果為:
注意:Citation類和Student類必須實現Serializable接口,否則會拋NotSerializableException異常。