原型模式(創建復雜實例)

源碼地址 https://github.com/DingMouRen/DesignPattern
原型模式.png
  • Prototype 抽象原型類 聲明一個克隆自身的接口
  • ConcreteProtype 具體的原型類,實現一個克隆自身的操作
定義

原型模式用原型實例指定創建對象的種類,并通過拷貝這些原型創建新的對象

使用場景
  • 類初始化需要消耗非常多的資源,包含數據、硬件資源等,通過原型拷貝避免這些消耗
  • 通過new創建一個對象,需要繁雜的數據準備或者訪問權限等,這里可以使用原型模式
  • 一個對象需要提供給其他對象訪問,各個調用者都有可能修改其值,可以使用原型模式拷貝多個對象供調用者使用,保護性拷貝。
協作

客戶端請求一個原型克隆自身。

舉個栗子

以文檔的拷貝為例,文檔中含有文本和圖片。為了安全,我們需要將原來的文檔拷貝一份副本,在副本上進行修改。

淺拷貝

淺拷貝是副本文檔的字段引用原始文檔字段的結果。Cloneable是標識性接口。注意:通過clone拷貝對象時,并不會執行構造函數。淺拷貝會有一個問題,就是下面添加圖片的時候,原型文檔也發生了變化。這是因為操作的images是同一個對象,通過深拷貝就可以避免這個問題。

//Cloneable代表Prototype,WordDocument代表ConcretePrototype
public class WordDocument implements Cloneable {
    //文本
    private String text;
    //圖片列表
    private ArrayList<String> images = new ArrayList<>();

    @Override
    protected Object clone()  {
        try {
            WordDocument document = (WordDocument) super.clone();
            document.text = this.text;
            document.images = this.images;
            return document;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    //打印文檔內容
    public void showDocument(){
        System.out.println("-------- 文檔內容: --------");
        System.out.println("Text:"+text);
        System.out.print("Images:");
        for (String imgName : images){
            System.out.print(imgName+",");
        }
        System.out.println();
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public ArrayList<String> getImages() {
        return images;
    }

    public void addImage(String img) {
        this.images.add(img);
    }
}

    public static void main(String[] args) {
        //構建文檔對象
        WordDocument originDoc = new WordDocument();
        //編輯文檔,添加圖片
        originDoc.setText("文本1");
        originDoc.addImage("圖片1");
        originDoc.addImage("圖片2");
        originDoc.addImage("圖片3");
        originDoc.addImage("圖片4");
        //以原型文檔為原型,拷貝一份副本
        WordDocument doc2 = (WordDocument) originDoc.clone();
        doc2.showDocument();
        //修改文檔副本,不會影響原始文檔
        doc2.setText("我修改了文本呢");
        doc2.addImage("新圖片");
        doc2.showDocument();

        //原型文檔
        originDoc.showDocument();

    }
深拷貝
//Cloneable代表Prototype,WordDocument代表ConcretePrototype
public class WordDocument implements Cloneable {
    //文本
    private String text;
    //圖片列表
    private ArrayList<String> images = new ArrayList<>();

    @Override
    protected Object clone()  {
        try {
            WordDocument document = (WordDocument) super.clone();
            document.text = this.text;
            //對圖片images對象也調用clone()函數,進行深拷貝
            document.images = (ArrayList<String>) this.images.clone();
            return document;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    //打印文檔內容
    public void showDocument(){
        System.out.println("-------- 文檔內容: --------");
        System.out.println("Text:"+text);
        System.out.print("Images:");
        for (String imgName : images){
            System.out.print(imgName+",");
        }
        System.out.println();
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public ArrayList<String> getImages() {
        return images;
    }

    public void addImage(String img) {
        this.images.add(img);
    }
}

    public static void main(String[] args) {
        //構建文檔對象
        WordDocument originDoc = new WordDocument();
        //編輯文檔,添加圖片
        originDoc.setText("文本1");
        originDoc.addImage("圖片1");
        originDoc.addImage("圖片2");
        originDoc.addImage("圖片3");
        originDoc.addImage("圖片4");
        //以原型文檔為原型,拷貝一份副本
       WordDocument doc2 = (WordDocument) originDoc.clone();
        doc2.showDocument();
        //修改文檔副本,不會影響原始文檔
        doc2.setText("我修改了文本呢");
        doc2.addImage("新圖片");
        doc2.showDocument();

        //原型文檔
        originDoc.showDocument();

    }
總結

原型模式可以解決構建復雜對象的資源消耗問題,能夠在某些場景下提高創建對象的效率,同時也可以保護原型文件,也就是保護性拷貝,某個對象對外可能是只讀的,為了防止外部對這個只讀對象進行修改。
優點:

原型模式是在內存中二進制流的拷貝,比new性能要好,特別是在循環體內創建大量對象時。
缺點:

因為是在內存中拷貝,所以構造函數式不會執行的。所以實際應用時一定要注意這個問題。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容