原型模式——文檔複製

文檔是我們在計算機上記錄文字等一個工具,通常一份文檔有一個大標題,也有許多個副標題。文檔的複製拷貝也很常見,那麼怎麼在程序設計中運用原型模式來模擬文檔的複製呢?
首先,通過UML圖大概瞭解一下原型模式吧:
這裏寫圖片描述

Client:客戶端類
Prototype:抽象類或接口,實現了Cloneable接口
ConcretePrototype:具體的原型類

既然需要模擬文檔複製,那麼就需要先建立一個文檔:

//Docment相當於ConcretePrototype,而Cloneable接口相當於Prototype
public class Document implements Cloneable{
    //主標題
    private String title;
    //所有副標題
    private ArrayList<String> subTitles = new ArrayList<>();

    @Override
    protected Document clone() throws CloneNotSupportedException {
        Document mNewspaper = (Document) super.clone();
        mNewspaper.title = title;
        mNewspaper.subTitles = subTitles;
        return mNewspaper;
    }

    //添加副標題
    public void addSubTitle(String content) {
        subTitles.add(content);
    }
    //設置主標題
    public void setTitle(String title) {
        this.title = title;
    }
    //文檔內容
    public String getDocText() {
        return title + " " + subTitles.toString();
    }
}

然後需要一個客戶端來進行復制:

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Document doc = new Document();
        doc.setTitle("標題");
        doc.addSubTitle("副標題1");
        doc.addSubTitle("副標題2");
        doc.addSubTitle("副標題3");
        System.out.println("原文檔:" + doc.getDocText());

        Document docCloning = doc.clone();
        System.out.println("複製的文檔:" + docCloning.getDocText());
    }
}

結果爲:

原文檔:標題 [副標題1, 副標題2, 副標題3]
複製的文檔:標題 [副標題1, 副標題2, 副標題3]

這就是原型模式的實現,但是卻會存在下列的問題,將代碼修改一下:

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Document doc = new Document();
        doc.setTitle("標題");
        doc.addSubTitle("副標題1");
        doc.addSubTitle("副標題2");
        doc.addSubTitle("副標題3");
        System.out.println("原文檔:" + doc.getDocText());

        Document docCloning = doc.clone();
        System.out.println("複製的文檔:" + docCloning.getDocText());
        System.out.println();
        //克隆的對象添加一個副標題,之後輸出克隆的和原來的DOC內容
        docCloning.addSubTitle("副標題4");
        System.out.println("複製的文檔:" + docCloning.getDocText());
        System.out.println("原文檔:" + doc.getDocText());
    }
}

結果爲:

原文檔:標題 [副標題1, 副標題2, 副標題3]
複製的文檔:標題 [副標題1, 副標題2, 副標題3]

複製的文檔:標題 [副標題1, 副標題2, 副標題3, 副標題4]
原文檔:標題 [副標題1, 副標題2, 副標題3, 副標題4]

會發現原來的文檔的副標題也修改了,這就引出了克隆的知識點:淺克隆與深克隆。
上述的克隆方式即爲淺克隆,雖然克隆出了一個新的文檔,但是他們對於subTitles的引用還是指向了同一個對象。要想避免出現這種問題,則需要使用深克隆,方法也很簡單:

@Override
    protected Document clone() throws CloneNotSupportedException {
        Document mNewspaper = (Document) super.clone();
        mNewspaper.title = title;
        //將引用的字段subTitles也進行克隆
        mNewspaper.subTitles = (ArrayList<String>) subTitles.clone();
        return mNewspaper;
    }

結果爲:

複製的文檔:標題 [副標題1, 副標題2, 副標題3, 副標題4]
原文檔:標題 [副標題1, 副標題2, 副標題3]

原型模式的應用相對簡單,只不過需要注意到什麼時候應該用淺克隆,或是深克隆。該模式適用於當需要一個相同的副本,要避免使用new來產生新對象導致資源消耗時使用。

原型模式的優缺點

  • 優點
    – 相對於用new產生一個對象來說,會消耗更少的資源,尤其是在循環體內。
  • 缺點
    -原型模式是克隆二進制流,並不會執行構造方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章