小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

大話設(shè)計(jì)模式筆記(七)の原型模式

 新進(jìn)小設(shè)計(jì) 2021-08-09

舉個(gè)栗子

問題描述

要求有一個(gè)簡歷類,必須要有姓名,可以設(shè)置性別和年齡,可以設(shè)置工作經(jīng)歷,最終需要三份簡歷。

簡單實(shí)現(xiàn)

簡歷類

/**
 * 簡歷類
 * Created by callmeDevil on 2019/7/13.
 */
public class Resume {
    
    private String name;
    private String sex;
    private String age;
    private String timeArea;
    private String company;
    
    public Resume (String name) {
        this.name = name;
    }

    /**
     * 設(shè)置個(gè)人信息
     * @param sex
     * @param age
     */
    public void setPersonalInfo(String sex, String age){
        this.sex = sex;
        this.age = age;
    }

    /**
     * 設(shè)置工作經(jīng)歷
     * @param timeArea
     * @param company
     */
    public void setWorkExperience(String timeArea, String company) {
        this.timeArea = timeArea;
        this.company = company;
    }

    /**
     * 顯示
     */
    public void display () {
        System.out.println(String.format("%s %s %s", name, sex, age));
        System.out.println(String.format("工作經(jīng)歷:%s %s", timeArea, company));
    }
 
    // 此處省略get、set方法
    
}

測試

/**
 * 測試
 * Created by callmeDevil on 2019/7/13.
 */
public class Test {

    public static void main(String[] args) {
        Resume resumeA = new Resume("callmeDevil");
        resumeA.setPersonalInfo("男", "24");
        resumeA.setWorkExperience("2018-2019", "偉大的航道");

        Resume resumeB = new Resume("callmeDevil");
        resumeB.setPersonalInfo("男", "24");
        resumeB.setWorkExperience("2018-2019", "偉大的航道");

        Resume resumeC = new Resume("callmeDevil");
        resumeC.setPersonalInfo("男", "24");
        resumeC.setWorkExperience("2018-2019", "偉大的航道");

        resumeA.display();
        resumeB.display();
        resumeC.display();
    }

}

測試結(jié)果

callmeDevil 男 24
工作經(jīng)歷:2018-2019 偉大的航道
callmeDevil 男 24
工作經(jīng)歷:2018-2019 偉大的航道
callmeDevil 男 24
工作經(jīng)歷:2018-2019 偉大的航道

存在的問題

跟手寫簡歷沒有差別,三份簡歷需要三份實(shí)例化,如果客戶需要二十份簡歷,那就得實(shí)例化二十次。

原型模式

定義

用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。

UML圖

代碼實(shí)現(xiàn)

/**
 * 簡歷類(實(shí)現(xiàn)JDK克隆接口)
 * Created by callmeDevil on 2019/7/13.
 */
public class Resume implements Cloneable{

    private String name;
    private String sex;
    private String age;
    private String timeArea;
    private String company;

    public Resume (String name) {
        this.name = name;
    }

    /**
     * 設(shè)置個(gè)人信息
     * @param sex
     * @param age
     */
    public void setPersonalInfo(String sex, String age){
        this.sex = sex;
        this.age = age;
    }

    /**
     * 設(shè)置工作經(jīng)歷
     * @param timeArea
     * @param company
     */
    public void setWorkExperience(String timeArea, String company) {
        this.timeArea = timeArea;
        this.company = company;
    }

    /**
     * 顯示
     */
    public void display () {
        System.out.println(String.format("%s %s %s", name, sex, age));
        System.out.println(String.format("工作經(jīng)歷:%s %s", timeArea, company));
    }

    /**
     * 實(shí)現(xiàn)克隆方法,可進(jìn)行自己的克隆邏輯
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // 此處省略get、set方法

}

測試

/**
 * 原型模式測試
 * Created by callmeDevil on 2019/7/13.
 */
public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
        Resume resumeA = new Resume("callmeDevil");
        resumeA.setPersonalInfo("男", "24");
        resumeA.setWorkExperience("2018-2019", "偉大的航道");

        // 只需要調(diào)用clone方法就可以實(shí)現(xiàn)新簡歷的生成,并且可以修改新簡歷的細(xì)節(jié)
        Resume resumeB = (Resume) resumeA.clone();
        resumeB.setWorkExperience("2019-2020", "新世界");

        Resume resumeC = (Resume) resumeA.clone();
        resumeC.setPersonalInfo("男", "25");

        resumeA.display();
        resumeB.display();
        resumeC.display();
    }

}

測試結(jié)果

callmeDevil 男 24
工作經(jīng)歷:2018-2019 偉大的航道
callmeDevil 男 24
工作經(jīng)歷:2019-2020 新世界
callmeDevil 男 25
工作經(jīng)歷:2018-2019 偉大的航道

好處

  • 一般在初始化的信息不發(fā)生變化的情況下,克隆是最好的方法。這既隱藏了對象創(chuàng)建的細(xì)節(jié),又對性能是大大的提高。
  • 不用重新初始化對象,而是動態(tài)的獲得對象運(yùn)行時(shí)的狀態(tài)。

淺復(fù)制與深復(fù)制

淺復(fù)制

在上面這個(gè)簡歷類中,如果字段是值類型(基本數(shù)據(jù)類型)的,則對該字段直接進(jìn)行復(fù)制;如果是引用類型(String等),則/復(fù)制引用/但不/復(fù)制引用的對象/;因此,原始對象及其副本引用同一對象。

在此之前,我們先做一個(gè)簡單的測試

    System.out.println("123" == "123");
    System.out.println("123".equals("123"));
    System.out.println(new String("123") == new String("123"));
    System.out.println(new String("123").equals(new String("123")));

相信有點(diǎn)基礎(chǔ)的都知道答案吧?就不賣弄了,直接上結(jié)果

true
true
false
true

至于結(jié)果為什么會這樣,網(wǎng)上也許多分析,此處重點(diǎn)在淺復(fù)制的講解,因此不做過多敘述。

帶著上面的理解再看下面的內(nèi)容。在可克隆的簡歷類例子中,基本數(shù)據(jù)類型就沒什么好測試的,有興趣的也可以將年齡改成 int 類型;對于其他 String 類型,就拿 company 字段來說,我們新建一個(gè)測試類看下是什么結(jié)果

public class Test2 {

    public static void main(String[] args) throws CloneNotSupportedException {
        Resume resumeA = new Resume("callmeDevil");
        resumeA.setWorkExperience("0", "偉大的航道");// 直接聲明String

        Resume resumeB = (Resume) resumeA.clone();

        // A 與 B 的公司兩種比較
        System.out.println(resumeA.getCompany() == resumeB.getCompany());
        System.out.println(resumeA.getCompany().equals(resumeB.getCompany()));

        resumeA.setWorkExperience("0", new String("偉大的航道"));//new 的方式創(chuàng)建String

        Resume resumeC = (Resume) resumeA.clone();

        // A 與 C 的公司兩種比較
        System.out.println(resumeA.getCompany() == resumeC.getCompany());
        System.out.println(resumeA.getCompany().equals(resumeC.getCompany()));
    }

}

比對第一個(gè)“123”的例子,稍微思考下在比對下面結(jié)果看是否一致

true
true
true
true

是的,這就是淺復(fù)制。不論A簡歷company直接聲明的還是 new 出來的,在clone方法中都只會對 company 字段復(fù)制一份引用而已。因此才會出現(xiàn) “==”“equal()”的結(jié)果都是“true”。對于引用類型來說,這個(gè)字段所在類實(shí)現(xiàn)了clone方法是不夠的,它只會對引用類型復(fù)制一份引用,那如果連引用類型的字段也要?jiǎng)?chuàng)建一份新的數(shù)據(jù),那便是 “深復(fù)制”。

  • 淺復(fù)制就是,被復(fù)制的對象的所有變量都含有與原來對象相同的值,而所有其他對象的引用都仍然只想原來的對象。
  • 深復(fù)制把引用對象的變量指向復(fù)制過的新對象,而不是援用的被引用的對象。

深復(fù)制

此處不糾結(jié)于如何對上述 String 的深復(fù)制?,F(xiàn)將簡歷類進(jìn)行改造,把“工作經(jīng)歷”抽出成另一個(gè)類 WorkExperience

簡歷類2

/**
 * 簡歷類2(深復(fù)制)
 * Created by callmeDevil on 2019/7/13.
 */
public class Resume2 implements Cloneable {

    private String name;
    private String sex;
    private String age;
    // 工作經(jīng)歷
    private WorkExperience work;

    public Resume2 (String name) {
        this.name = name;
        this.work = new WorkExperience();
    }
    
    private Resume2(WorkExperience work) throws CloneNotSupportedException {
        this.work = (WorkExperience) work.clone();
    }

    /**
     * 設(shè)置個(gè)人信息
     * @param sex
     * @param age
     */
    public void setPersonalInfo(String sex, String age){
        this.sex = sex;
        this.age = age;
    }

    /**
     * 設(shè)置工作經(jīng)歷
     * @param timeArea
     * @param company
     */
    public void setWorkExperience(String timeArea, String company) {
        // 此處賦值給 work 對象
        this.work.setWorkDate(timeArea);
        this.work.setCompany(company);
    }

    /**
     * 顯示
     */
    public void display () {
        System.out.println(String.format("%s %s %s", name, sex, age));
        // 此處顯示 work 對象的值
        System.out.println(String.format("工作經(jīng)歷:%s %s", work.getWorkDate(), work.getCompany()));
    }

    /**
     * 實(shí)現(xiàn)克隆方法,可進(jìn)行自己的克隆邏輯
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 調(diào)用私有的構(gòu)造方法,讓“工作經(jīng)歷”對象克隆完成,然后再給這個(gè)“簡歷”對象
        // 相關(guān)的字段賦值,最終返回一個(gè)深復(fù)制的簡歷對象
        Resume2 obj = new Resume2(this.work);
        obj.setName(this.name);
        obj.setSex(this.sex);
        obj.setAge(this.age);
        return obj;
    }

    // 此處省略get、set方法
    
}

工作經(jīng)歷

/**
 * 工作經(jīng)歷
 * Created by callmeDevil on 2019/7/13.
 */
public class WorkExperience implements Cloneable{

    private String workDate;

    private String company;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // 此處省略get、set方法
    
}

測試類

/**
 * 深復(fù)制測試
 * Created by callmeDevil on 2019/7/13.
 */
public class TestDeepClone {

    public static void main(String[] args) throws CloneNotSupportedException {
        Resume2 resumeA = new Resume2("callmeDevil");
        resumeA.setPersonalInfo("男", "24");
        resumeA.setWorkExperience("2018-2019", "偉大的航道");

        Resume2 resumeB = (Resume2) resumeA.clone();
        resumeB.setWorkExperience("2019-2020", "新世界");

        Resume2 resumeC = (Resume2) resumeA.clone();
        resumeC.setWorkExperience("2020-XXXX", "木葉忍者村");

        resumeA.display();
        resumeB.display();
        resumeC.display();
    }

}

測試結(jié)果

callmeDevil 男 24
工作經(jīng)歷:2018-2019 偉大的航道
callmeDevil 男 24
工作經(jīng)歷:2019-2020 新世界
callmeDevil 男 24
工作經(jīng)歷:2020-XXXX 木葉忍者村

可以看到,每次克隆都能將簡歷類中的工作經(jīng)歷類一同新建,而不是單純的同個(gè)對象進(jìn)行改變內(nèi)容。如果是淺復(fù)制的實(shí)現(xiàn),那么在相同測試類中會出現(xiàn)什么結(jié)果呢?應(yīng)該能猜到吧,那就是三次輸出都是一樣的。
對于工作經(jīng)歷類淺復(fù)制實(shí)現(xiàn)本文就不描述了,有興趣的可以自行測試,很簡單,需要修改的地方有這么兩處:

  • 簡歷類實(shí)現(xiàn)的克隆方法中直接調(diào)用 super.clone() 而不需要重寫。
  • 取消工作經(jīng)歷類實(shí)現(xiàn)克隆接口及其方法。

只需要更改這兩處,在相同的測試類中就能看到以下結(jié)果

callmeDevil 男 24
工作經(jīng)歷:2020-XXXX 木葉忍者村
callmeDevil 男 24
工作經(jīng)歷:2020-XXXX 木葉忍者村
callmeDevil 男 24
工作經(jīng)歷:2020-XXXX 木葉忍者村

看到此處就不需要解釋了吧,每次克隆只是新實(shí)例化了“簡歷”,但三個(gè)“簡歷”中的“工作經(jīng)歷”都是同一個(gè),每次 set值 的時(shí)候都必將影響到所有對象,所以輸出的工作經(jīng)歷都是相同的。這也同時(shí)說明了實(shí)現(xiàn)深復(fù)制的必要條件

  • 需要實(shí)現(xiàn)深復(fù)制的引用類型字段的類(比如上文中的工作經(jīng)歷)必須實(shí)現(xiàn) Cloneable 接口
  • 該字段的所屬類(比如上文中的簡歷)實(shí)現(xiàn)的克隆方法中必須對該字段進(jìn)行克隆與賦值

做到以上兩點(diǎn),即可將原本淺復(fù)制的功能轉(zhuǎn)變?yōu)?strong>深復(fù)制。

總結(jié)

原型模式無非就是對指定創(chuàng)建的原型實(shí)例進(jìn)行復(fù)制,再對新對象另做操作,省去重新 new 的過程。其中復(fù)制便分為淺復(fù)制深復(fù)制。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多