設計模式學習--原型模式
原型模式(Prototype):用原型實例指定創建對象的 種類,並且通過拷貝這些原型創建新的對象。
原型模式結構圖:
原型模式涉及深克隆和淺克隆。
案例需求:制作一份簡歷,並復制三份。
第一次克隆實現:
1:創建簡歷類。
package PrototypeModel; /** * 簡歷類 * @author 我不是張英俊 * */ public class Resume implements Cloneable { private String name; private String sex; private String age; privateString timeArea; private String company; public Resume(){ } public Resume(String name){ this.name=name; } //設置個人信息 public void SetPersonalInfo(String sex,String age){ this.sex=sex; this.age=age; } //設置工作經歷 public voidSetWorkExperience(String timeArea,String company){ this.timeArea=timeArea; this.company=company; } //顯示 public void Display(){ System.out.println(name+" "+sex+" "+age); System.out.println("工作經歷:"+timeArea+" "+company); } public Object Copy() throwsCloneNotSupportedException { return this; } public Object clone() throws CloneNotSupportedException{ //調用父類Object中的clone方法實現淺克隆 return super.clone(); } }
2:創建測試類
package PrototypeModel; /** * 簡歷復印,打印一份簡歷,並復印三份; * 原型模式:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。 * @author 我不是張英俊 * */ public class Test { public static void main(String[] args) throws CloneNotSupportedException { Resume a=new Resume("旺財"); a.SetPersonalInfo("男", "19"); a.SetWorkExperience("1998-2-3", "百度"); /** * Cpoy 方法中的是return this, * 返回的是索引,即返回的是指向堆中a對象的索引, * 所以,不論怎麽重新改變屬性,最終改變的都是a對象中的屬性, * 而此時,並沒有在堆中重新copy出兩個新的對象b和c。 * 所以,應該用clone方法來實行, * 繼承Cloneable接口,並且重寫Object中的clone方法。 * Cloneable接口是一個空的接口,它只是表明,可以重寫clone方法,若不實現此接口,不可以重寫clone方法 * 此處使用的是淺克隆。 */ Resume b= (Resume) a.Copy(); Resume b1=(Resume) a.clone(); b.SetWorkExperience("2019-02-06", "360"); Resume c=(Resume) a.Copy(); Resume c1=(Resume) a.clone(); a.SetWorkExperience("2016-03-02", "阿裏"); System.out.println("a= "+a); System.out.println("b= "+b); System.out.println("c= "+c); System.out.println("b1= "+b1); System.out.println("c1= "+c1); /** * 控制臺輸出發現克隆的索引不同,即創建出了新的對象。 */ a.Display(); b.Display(); c.Display(); a.Display(); b1.Display(); c1.Display(); } }
3:控制臺
a= [email protected] b= [email protected] c= [email protected] b1= [email protected] c1= [email protected] 旺財 男 19 工作經歷:2016-03-02 阿裏 旺財 男 19 工作經歷:2016-03-02 阿裏 旺財 男 19 工作經歷:2016-03-02 阿裏 旺財 男 19 工作經歷:2016-03-02 阿裏 旺財 男 19 工作經歷:1998-2-3 百度 旺財 男 19 工作經歷:2019-02-06 360
a,b,c三個的地址相同,說明return this返回當前對象的時候返回的是索引,他們指向同一個對象。
而b1,c1地址不同,說明是利用clone方法創建了新的對象。
super.clone()返回的是Object類型的。利用Object類中的clone方法來進行淺克隆。重寫Object類中的clone方法需要實現Cloneable接口。
其中Cloneable接口是一個空接口,它只是表明你可以重寫clone方法,不實現重寫的話,會拋出異常。
第二次克隆實現
事實上在實際開發過程中,工作經歷通常會做成工作經歷類,這樣,就需要深克隆。
先看如果使用淺克隆導致的問題:
1:創建工作經歷類。
package PrototypeModel2; public class workExperence { private String workDate; private String company; public String getWorkDate() { return workDate; } public void setWorkDate(String workDate) { this.workDate = workDate; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } }
2:創建簡歷類。
package PrototypeModel2; public class Resume implements Cloneable { private String name; private String sex; private String age; private workExperence work; public Resume(String name){ this.name=name; work=new workExperence(); } //設置個人信息 public void setPersonalInfo(String sex,String age){ this.sex=sex; this.age=age; } //設置工作經歷 public void setWorkExperience(String workDate,String company){ work.setCompany(company); work.setWorkDate(workDate); } //顯示 public void display(){ System.out.println(name+" "+sex+" "+age); System.out.println(work.getCompany()+" "+work.getWorkDate()); } public Object clone() throws CloneNotSupportedException{ return super.clone(); } }
3:測試類。
package PrototypeModel2; /** * 淺克隆會導致的問題 * 制作簡歷 * 實際開發中,會將工作經歷作為一個類, * @author 我不是張英俊 * */ public class Test { public static void main(String arg[]) throws CloneNotSupportedException{ Resume a=new Resume("旺財"); a.setPersonalInfo("男", "26"); a.setWorkExperience("2016-1017", "阿裏"); Resume b=(Resume) a.clone(); b.setWorkExperience("2017-2018", "360"); Resume c=(Resume) a.clone(); a.setWorkExperience("2018-2019", "騰訊"); a.display(); b.display(); c.display(); } }
4:控制臺。
旺財 男 26 騰訊 2018-2019 旺財 男 26 騰訊 2018-2019 旺財 男 26 騰訊 2018-2019
原因:堆內存中只存在一個workExperience類,所以在修改的時候,總是修改同一個類中的數據,雖然克隆了不同的Resume對象,但不同的Resume對象確是調用同一個workExperience中的數據,所以最後輸出的都是最後修改的。
因為clone()方法,對於引用類型,克隆的是其引用,所以,當改變值得時候,就會出現相同的結果。因為三個引用都指向了同一個對象,即唯一的workExperience對象。
如果想顯示不同的,就必須對workExperience進行克隆,這樣每一個引用不同的workExperience就不會出現這種問題。
第三次克隆實現:
1:創建工作經歷類
package PrototypeModel1; /** * 工作經歷類 * @author 我不是張英俊 * */ public class WorkExperience implements Cloneable { private String workDate; private String company; public String getWorkDate() { return workDate; } public void setWorkDate(String workDate) { this.workDate = workDate; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public Object clone() throws CloneNotSupportedException{ return super.clone(); } }
2:創建一個簡歷類。
package PrototypeModel1; public class Resume implements Cloneable { private String name ; private String sex; private String age; private WorkExperience work; public Resume(String name){ this.name=name; work=new WorkExperience(); } /* *提供clone方法調用的私有構造函數,以便克隆“工作經歷”的數據 */ private Resume(WorkExperience work) throws CloneNotSupportedException{ this.work=(WorkExperience) work.clone(); } //設置個人信息 public void setPersonalInfo(String sex,String age){ this.sex=sex; this.age=age; } //設置工作經歷 public void setWorkExperience(String workDate,String company){ work.setCompany(company); work.setWorkDate(workDate); } //展示 public void display(){ System.out.println(name+" "+sex+" "+age); System.out.println("工作經歷 "+work.getCompany()+" "+work.getWorkDate()); } public Object clone() throws CloneNotSupportedException{ /** * 調用私有的構造方法,讓“工作經歷”克隆完成,然後再給這個“簡歷” * 對象相關字段賦值,最終返回一個深克隆的簡歷對象。 */ Resume obj=new Resume(this.work); obj.age=this.age; obj.name=this.name; obj.sex=this.sex; return obj; } }
3:創建一個測試類。
package PrototypeModel1; /** * 簡歷復印, * 原型模式, * 深拷貝和淺拷貝 * @author 我不是張英俊 * */ public class Test { public static void main(String[] args) throws CloneNotSupportedException { Resume a =new Resume("旺財"); a.setPersonalInfo("男", "19"); a.setWorkExperience("2019-2020", "阿裏"); Resume b=(Resume)a.clone(); b.setWorkExperience("2017-2018", "騰訊"); Resume c=(Resume)a.clone(); c.setWorkExperience("2016-2017", "華為"); a.display(); b.display(); c.display(); } }
4:控制臺。
旺財 男 19
工作經歷 阿裏 2019-2020
旺財 男 19
工作經歷 騰訊 2017-2018
旺財 男 19
工作經歷 華為 2016-2017
利用深克隆解決問題。創建了堆內存中實際存在了三個workExperience對象。
總結:理解尚淺,暫時未想到。
設計模式學習--原型模式