Android設計模式之原型模式

原型模式

1.定義:

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

2.使用場景:

  • 類初始化需要消耗非常多的資源,這個資源包括數(shù)據(jù)、硬件資源等,通過原型copy避免了這些消耗;
  • 通過new產(chǎn)生一個對象需要非常繁瑣的數(shù)據(jù)準備或訪問權(quán)限,這時可以使用原型模式;
  • 一個對象需要提供給其他對象訪問,而且各個調(diào)用者可能都需要修改其值時,可以考慮使用原型模式copy多個對象供調(diào)用者使用,即保護性copy。
    注意:
    1.通過實現(xiàn)Cloneable接口的原型模式再調(diào)用clone函數(shù)構(gòu)造實例時,并不一定比通過new操作效速度快,只有當通過new構(gòu)造對象較為耗時或成本較高時,通過clone方法才能獲得效率上的提升。因此,在使用Cloneable時需要考慮構(gòu)建對象的成本以及一些效率上的測試。
    2.實現(xiàn)原型模式不一定非要實現(xiàn)Cloneable接口,也有其他的實現(xiàn)方式。

3.UML圖

4.詳解:

原型模式是一個創(chuàng)建型模式,‘原型’二字表明該模式應該有一個樣板實例,提供給用戶訪問copy。用戶從這個樣板對象中復制出一個內(nèi)部屬性一致的對象的過程,稱為克隆。被復制的樣板對象就是‘原型’。原型模式多用于創(chuàng)建復雜的或構(gòu)造耗時的實例,因為這些情況下,復制一個已經(jīng)存在的實例可使程序運行效率更高。
下面用代碼舉例闡述:

public static class WordDocument implements Cloneable {
        private String text;
        private ArrayList<String> images = new ArrayList<>();

        public WordDocument() {
            System.out.println("constructor start");
        }

        @Override
        protected WordDocument clone() {
            try {
                WordDocument doc = (WordDocument) super.clone();
                doc.text = text;
                doc.images = images;//淺拷貝
                return doc;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }

        public String getText() {
            return text;
        }

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

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

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

        public void showDocument() {
            System.out.println("text:" + text);
            System.out.print("images:");
            for (int i = 0; i < images.size(); i++) {
                if (i == images.size() - 1) {
                    System.out.print(images.get(i) + "\n");
                } else {
                    System.out.print(images.get(i) + ",");
                }
            }
        }
    }

測試代碼:

public static void main(String[] args) {
        WordDocument originDoc = new WordDocument();
        originDoc.setText("原文檔text");
        originDoc.addImage("img1");
        originDoc.addImage("img2");
        originDoc.addImage("img3");
        originDoc.showDocument();
        System.out.println("=========================");

        WordDocument newDoc = originDoc.clone();
        newDoc.showDocument();
        System.out.println("=========================");

        newDoc.setText("修改后的text");
        newDoc.addImage("img4");
        newDoc.showDocument();

        System.out.println("=========================");
        originDoc.showDocument();
        /**
         * 輸出結(jié)果:
         constructor start
         text:原文檔text
         images:img1,img2,img3
         =========================
         text:原文檔text
         images:img1,img2,img3
         =========================
         text:修改后的text
         images:img1,img2,img3,img4
         =========================
         text:原文檔text
         images:img1,img2,img3,img4
         */
    }

這里的WordDocument 就是所謂的‘原型’,它里面有文字描述與圖片url?,F(xiàn)在用戶需要重新編輯該文檔,又想不破壞原文檔,于是用戶需要復制一份原文檔,在拷貝文檔上編輯,詳細過程見測試代碼。
從上面的測試結(jié)果可以得出如下結(jié)論:

  • 通過clone 拷貝對象時,并不會執(zhí)行構(gòu)造函數(shù),因此,如果在構(gòu)造函數(shù)中需要初始化操作的類型,在使用Cloneable實現(xiàn)拷貝時,需注意構(gòu)造函數(shù)不會執(zhí)行的問題。
  • 副文檔修改了文本內(nèi)容,原文檔內(nèi)容不受影響,這樣保證了原文檔的安全性;
  • 但是,細心的你也許發(fā)現(xiàn)了,在副文檔中添加img4,原文檔也會有img4。說好的安全呢?瞬間被打臉,有木有?其實這個例子是淺拷貝(也稱為‘影子拷貝’),這份拷貝并不是將原始文檔的所有字段都重構(gòu)了一份,而是副文檔的字段引用了原始文檔的字段,即原文檔與副文檔的字段images其實指向同一個地址,于是才會出現(xiàn)上述情況。那么這種情況該如何規(guī)避?答案是深拷貝!即在拷貝對象時,對于引用型的字段也采用拷貝的形式,而不是上面的單純引用的方式。
    下面修改clone方法:doc.images = (ArrayList<String>) images.clone(),即深拷貝。
    @Override
        protected WordDocument clone() {
            try {
                WordDocument doc = (WordDocument) super.clone();
                doc.text = text;
                doc.images = (ArrayList<String>) images.clone();//深拷貝
                return doc;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }

測試代碼不變,但是輸出的結(jié)果卻變了,如下:

        /**
         * 輸出結(jié)果:
         constructor start
         text:原文檔text
         images:img1,img2,img3
         =========================
         text:原文檔text
         images:img1,img2,img3
         =========================
         text:修改后的text
         images:img1,img2,img3,img4
         =========================
         text:原文檔text
         images:img1,img2,img3
         */

修改了副文檔的images,原文檔也沒有改變,很安全了。
原型模式是非常簡單的模式,它的核心問題就是對原始對象進行拷貝,在這個模式的使用過程中需要注意的一點就是深、淺拷貝的問題。在實際開發(fā)過程中,為了減少錯誤,盡量使用深拷貝原型模式,避免操作副本對象時,影響了原始對象的屬性

5.代碼托管地址

原型模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 從Java的角度看,使用原型模式有個明顯的特點,就是實現(xiàn)cloneable的clone()方法。 原型模式,能快速...
    博為峰51Code教研組閱讀 276評論 0 0
  • 前言 Android的設計模式系列文章介紹,歡迎關(guān)注,持續(xù)更新中: Android的設計模式-設計模式的六大原則一...
    四月葡萄閱讀 5,687評論 4 10
  • 目錄 定義 使用場景 UML類圖 簡單實現(xiàn) 使用Cloneable接口 不實現(xiàn)Cloneable接口 問題 深拷貝...
    喵了個嗚s閱讀 938評論 0 2
  • 哪怕現(xiàn)實磕疼了你,依然長成玫瑰的模樣,一路芳香。 天下沒有不散的筵席,當時人再好,情再真,抵不過時光流轉(zhuǎn),沖得七零...
    西域婉風閱讀 244評論 0 2
  • -s, —slient 沉默模式, 不顯示具體的過程, 看一下有沒有這個參數(shù)的區(qū)別 -w, --write-out...
    wasw100閱讀 794評論 0 2

友情鏈接更多精彩內(nèi)容