1. 程式人生 > >設計模式學習--原型模式

設計模式學習--原型模式

需要 dex throws 測試類 enc 接口 打印 getc 創建對象

原型模式(Prototype):用原型實例指定創建對象的 種類,並且通過拷貝這些原型創建新的對象。

原型模式結構圖:

技術分享

原型模式涉及深克隆和淺克隆。

案例需求:制作一份簡歷,並復制三份。

第一次克隆實現:

1:創建簡歷類。

package PrototypeModel;

/**
 * 簡歷類
 * @author 我不是張英俊
 *
 */
public class Resume implements Cloneable {

    private String name;
    private String sex;
    private String age;
    private
String 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 void
SetWorkExperience(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() throws
CloneNotSupportedException { 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對象。

總結:理解尚淺,暫時未想到。

設計模式學習--原型模式