設計模式(三)---原型模式
吐槽
今天帶貓貓去打針,然後她各種皮,差點從袋子裡面跑出去了emmmmm,早上上課時候,編譯原理上上課居然就聽不懂了,很尷尬,趕緊回去補。
什麼叫原型模式
就是類似鳴人的影分身之術,可以克隆物件 定義:用原型例項指向建立物件的種類,並通過複製這些原型建立新的物件
原型模式使用的場景
- 當初始化類物件需要消耗非常多資源,或者說要進繁瑣的資料準備或者許可權,如果想簡化建立,可以使用原型模式
- 一個物件要提供給其他物件訪問的時候,而且個個呼叫者都可能改變其值的時候,可以用原型模式複製個個物件提供呼叫者使用,即保護性拷貝
原型模式下的各種角色
- Client —— 客戶端使用者,呼叫類
- ConcretePrototype —— 實現Prototype介面的類,這些類真正實現克隆自身的相關程式碼
- Prototype —— 宣告一個克隆自身的介面,用於約束想要克隆自己的類,要求實現定義的克隆方法。
物件的拷貝
在Java中,如果我們將原始物件的值賦給另一個物件,就是值的傳遞,如
int a = 1;
int b = a;
如果將引用型別的值賦給另一個物件,則是引用的傳遞,如
String[] a = new String[5];
String[] b = a;//這裡b只是指向了a的引用
在java中
==,如果是對比的基本資料型別(int,long等),比較儲存的值是否相等,
equals,不能用於比較基本資料型別,如果沒對equals()方法進行 重寫,比較的是指向的物件地址,如果想要比較物件內容,需要自行重寫 方法,做相應的判斷
java中的克隆方法及其使用過程
- 對任何的物件x,都有:x.clone()!=x ,即不是同一物件
- 對任何的物件x,都有:x.clone().getClass==x.getClass(),即物件型別一致
- 如果物件obj的equals()方法定義恰當的話,那麼obj.clone().equals(obj) 應當是成立的
使用clone()方法的步驟:
java在處理基本資料型別(例如int,double,char等),都採用按值傳遞(傳遞的是輸入引數的複製),除此之外的其他型別都採用按引用傳遞(傳遞的是物件的一個引用)。物件除了在函式呼叫時是引用傳遞,在使用“=”賦值時也採用引用傳遞
實用流程
1 先寫個引用類:Student.java
public class Student {
private String name; //名字
Student(String name){
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name:"+name;
}
}
2實現Cloneable介面的類:CloneStudent.java,核心就是重寫clone方法而已
public class CloneStudent implements Cloneable {
private int age; //年齡
private Student student;//名字
private String king;//學生的型別
CloneStudent(int age,Student student,String king){
System.out.println("執行了構造方法");
this.age = age;
this.student = student;
this.king = king;
}
@Override
protected Object clone() throws CloneNotSupportedException {
CloneStudent cloneStudent = null;
try {
cloneStudent = (CloneStudent)super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return cloneStudent;
}
public int getAge() {
return age;
}
public String getKing() {
return king;
}
public Student getStudent() {
return student;
}
public void setAge(int age) {
this.age = age;
}
public void setKing(String king) {
this.king = king;
}
public void setStudent(Student student) {
this.student = student;
}
@Override
public String toString() {
return "CloneStudent["+"age = "+age+"Student"+student.toString()+"kind"+king;
}
}
3 呼叫類
CloneStudent cloneStudent1 = new CloneStudent(10, new Student("笑笑"),"哈哈");
try {
CloneStudent cloneStudent2 = (CloneStudent)cloneStudent1.clone();
System.out.println("Student1.equals(Student) "+cloneStudent1.equals(cloneStudent2));
System.out.println("student1==student2"+(cloneStudent1==cloneStudent2));
System.out.println(cloneStudent1.getClass()==cloneStudent2.getClass());
System.out.println(cloneStudent1.toString());
System.out.println(cloneStudent2.toString());
cloneStudent1.setAge(200);
System.out.println(cloneStudent1.toString());
System.out.println(cloneStudent2.toString());
cloneStudent2.getStudent().setName("啦啦");
System.out.println(cloneStudent1.toString());
System.out.println(cloneStudent2.toString());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
執行結果:
以上結果發現:
- cloneStudent2是cloneStudent1克隆出來的
- 通過克隆的時候不會執行建構函式
- 克隆會生成的新的物件變數,指向的卻是同一個記憶體地址
- 克隆前後資料型別一致
- 克隆的時候,類中基本資料型別的屬性會新建,但是引用型別的 只會生成個新的引用變數,引用變數的地址依舊指向同一個記憶體地址
深拷貝和淺拷貝
淺拷貝:只新建基本型別資料,不新建引用型別資料 深拷貝:引用型別資料也新建
如何將淺拷貝轉換成深拷貝? 有兩種方法
1引用型別也實現Cloneable介面,然後實現clone方法
先把Student.java這個類實現介面,然後寫Clone方法
public class Student implements Cloneable{
private String name; //名字
Student(String name){
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "name:"+name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student student = null;
student = (Student)super.clone();
return student;
}
}
然後再在介面實現類CloneStudent修改clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
CloneStudent cloneStudent = null;
try {
cloneStudent = (CloneStudent)super.clone();
cloneStudent.setStudent((Student)this.getStudent().clone());
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return cloneStudent;
}
然後重新執行發行結果: 然後結果發現我們cloneStudent2物件修改了name字串,cloneStudent1物件的name字串並沒有變化
總結
原型模式就是clone方法的使用,推薦用深拷貝的方式 淺拷貝適用於 物件只包含原始資料域或者不可變物件域的時候,提高效率 該模式的優點是: 1.簡化物件建立過程,當物件建立比較煩瑣時,可提高建立效率 2.深拷貝可儲存物件狀態,可將物件拷貝後儲存起來,需要的時候恢復 缺點是: 克隆時候不會執行構造方法,所以很尷尬