簡易理解設(shè)計(jì)模式之:原型模式——深垂睬、淺拷貝的概念

介紹:

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

類圖:

原型模式UML類圖.png

Prototype(抽象原型類):抽象類或接口钳枕,聲明復(fù)制方法。
ConcretePrototype(具體原型類):具體被復(fù)制的對象赏壹。
Client(客戶端類):調(diào)用類鱼炒。

用法:

? 類初始化時(shí)候需要消耗非常多資源,通過原型拷貝避免這些消耗蝌借。
? 通過new產(chǎn)生一個(gè)對象時(shí)候需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限時(shí)昔瞧。
? 一個(gè)對象需要提供給其它對象使用,并且各個(gè)調(diào)用者都可能修改其值時(shí)菩佑,可以考慮使用自晰,即保護(hù)性拷貝。

個(gè)人理解:
? 在某個(gè)時(shí)刻從某個(gè)類的實(shí)例到一個(gè)與此時(shí)此刻相同又不相互影響的實(shí)例稍坯,實(shí)際上就是動態(tài)抽取當(dāng)前對象運(yùn)行時(shí)的狀態(tài)酬荞。
? 當(dāng)然我們并不是在任何情況下創(chuàng)建復(fù)雜對象都適合用這種模式,例如我需要初始化一個(gè)復(fù)雜且干凈的類時(shí)還是考慮使用工廠方法模式瞧哟。

例子:

原型模式的原理是對象拷貝混巧。在Java中使用clone方法復(fù)制一個(gè)對象,就是原型模式的體現(xiàn)了勤揩。日常工作中咧党,在我們編輯Word文檔的時(shí)候,為了安全起見會拷貝一份當(dāng)前文檔的狀態(tài)再進(jìn)行修改陨亡,下面我們以這個(gè)例子說明一下這個(gè)模式:

需求:實(shí)現(xiàn)文檔拷貝

1傍衡、引用拷貝

1.1深员、Word中有文字和圖片,因此創(chuàng)建一個(gè)Word文檔對象蛙埂。

public class WordDocument {
    private String mText;
    private ArrayList<String> mImages = new ArrayList<>();

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

    public void addImages(String img) {
        this.mImages.add(img);
    }

    public void show() {
        System.out.println("------- Word Start ------");
        System.out.println("文本內(nèi)容:" + mText);
        for (String imgs : mImages) {
            System.out.println("圖片名稱:" + imgs);
        }
        System.out.println("------- Word  End  ------");
    }
}

1.2辨液、用引用拷貝實(shí)現(xiàn)

實(shí)現(xiàn)復(fù)制功能很多初學(xué)者第一時(shí)間可能是想到這樣寫:

public class Client {
    public static void main(String[] args) {
        WordDocument a = new WordDocument();
        a.setText("啦啦啦");

        //拷貝a對象
        WordDocument b = a;
        //修改b的內(nèi)容
        b.setText("呵呵呵");
    }
}

輸出結(jié)果卻不如人意,修改b的時(shí)候把原始的文檔a也同時(shí)修改了:

//a的原始內(nèi)容輸出:
文本內(nèi)容:啦啦啦
//修改b后輸出a:
文本內(nèi)容:呵呵呵
//修改b后輸出b:
文本內(nèi)容:呵呵呵

1.3箱残、引用拷貝概念
兩個(gè)對象的引用相同,都指向同一個(gè)對象止吁,就叫引用拷貝被辑。我們抽離出核心代碼解釋一下:

WordDocument a = new WordDocument();
WordDocument b = a;

在內(nèi)存中發(fā)生如下事情:


引用拷貝.png

本質(zhì)上是復(fù)制了一個(gè)引用b,同時(shí)指向了堆區(qū)的對象敬惦。所以通過b將"啦啦啦"修改為"呵呵呵"后盼理,a的輸出結(jié)果也為"呵呵呵"了。所以我們怎么做才能從堆區(qū)中復(fù)制一個(gè)對象呢俄删?

2宏怔、對象拷貝

2.1、使用原型模式實(shí)現(xiàn)
在java中畴椰,Cloneable接口相當(dāng)于Prototype臊诊,而我們的WordDocument就相當(dāng)于ConcretePrototype了。因此我們修改下1.1中的類:

public class WordDocument implements Cloneable {
     //....省略部分代碼
    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            WordDocument doc = (WordDocument)super.clone();
            doc.mText = this.mText;
            doc.mImages = this.mImages;
            return doc;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

2.2斜脂、修改一下1.1中的實(shí)現(xiàn)部分:

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        WordDocument a = new WordDocument();
        a.setText("啦啦啦");
        a.show();

        //拷貝a對象
        WordDocument b = (WordDocument) a.clone();
        //修改b的內(nèi)容
        b.setText("呵呵呵");
    }
}

輸出結(jié)果:

//a的原始內(nèi)容輸出:
文本內(nèi)容:啦啦啦
//修改b后輸出a:
文本內(nèi)容:啦啦啦
//修改b后輸出b:
文本內(nèi)容:呵呵呵

2.3抓艳、對象拷貝概念
從堆區(qū)中復(fù)制一個(gè)類型和值都是之前的一樣的對象,就叫對象拷貝帚戳。深拷貝和淺拷貝都是對象拷貝玷或。關(guān)鍵代碼如下:

WordDocument a = new WordDocument();
WordDocument b = (WordDocument) a.clone();

我們再看下內(nèi)存中是怎樣的:


對象拷貝.png

通過clone()方法,堆區(qū)的"啦啦啦"復(fù)制出一個(gè)對象片任,b引用之后將它改為"呵呵呵"偏友。它們的內(nèi)存地址都是不同的。

3对供、淺拷貝與深拷貝

3.1位他、淺拷貝的實(shí)現(xiàn)
我們繼續(xù)完善我們的代碼,加入圖片部分的邏輯:

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        WordDocument a = new WordDocument();
        a.setText("啦啦啦");
        a.addImages("圖片1.jpg");
        a.addImages("圖片2.jpg");
        a.addImages("圖片3.jpg");
        a.show();

        WordDocument b = (WordDocument) a.clone();
        //修改B的內(nèi)容
        b.setText("呵呵呵");
        b.addImages("呵呵.jpg");
        //同時(shí)輸出
        a.show();
        b.show();
    }
}

輸出結(jié)果:

------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
------- Word  End  ------
------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
圖片名稱:呵呵.jpg
------- Word  End  ------
------- Word Start ------
文本內(nèi)容:呵呵呵
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
圖片名稱:呵呵.jpg
------- Word  End  ------

我們不難發(fā)現(xiàn)犁钟,修改后圖片部分的內(nèi)容輸出竟然是一致的棱诱。我們添加了"呵呵.jpg"直接插入了原來的數(shù)組里面了。因?yàn)樵谖覀?.1中的clone()方法只是簡單的進(jìn)行淺拷貝涝动,mImages只是單純指向了this.mImages的引用迈勋,并沒有重新構(gòu)造一個(gè)mImages對象,這樣導(dǎo)致了b中的mImages與原始文檔是同一個(gè)對象了醋粟。

3.2靡菇、淺拷貝的概念
上述例子在內(nèi)存的情況如下:


淺拷貝.png

在淺拷貝中僅僅克隆基本類型的變量重归,而不克隆引用類型的變量。String類型也是一種引用類型厦凤,為什么卻不受影響呢鼻吮?

String類型非常特殊,它屬于引用數(shù)據(jù)類型较鼓,不屬于基本數(shù)據(jù)類型椎木,但是String類型的數(shù)據(jù)是存放在常量池中的,也就是無法修改的博烂。

3.3香椎、深拷貝的實(shí)現(xiàn)
我們將2.1的clone方法修改,克隆方法中的對象也執(zhí)行一下clone()方法:

public class WordDocument implements Cloneable {
    //省略部分代碼
    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            WordDocument doc = (WordDocument)super.clone();
            doc.mText = this.mText;
            doc.mImages = (ArrayList<String>) this.mImages.clone();
            return doc;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

再執(zhí)行3.1中Client類的代碼禽篱,效果如下:

------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
------- Word  End  ------
------- Word Start ------
文本內(nèi)容:啦啦啦
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
------- Word  End  ------
------- Word Start ------
文本內(nèi)容:呵呵呵
圖片名稱:圖片1.jpg
圖片名稱:圖片2.jpg
圖片名稱:圖片3.jpg
圖片名稱:呵呵.jpg
------- Word  End  ------

我們看到畜伐,加了"呵呵.jpg"之后并不影響原本的對象了。再看一下內(nèi)存:


深拷貝.png
4躺率、總結(jié)

原型模式原理就是對象拷貝玛界,而對象拷貝中分為淺拷貝和深拷貝。這個(gè)也是值得注意的問題悼吱。為了減少使用錯誤我認(rèn)為都應(yīng)該盡可能使用深拷貝慎框,避免操作副本時(shí)影響原始對象的問題。

淺拷貝:僅僅復(fù)制基本類型的變量舆绎,而不復(fù)制引用類型的變量鲤脏。
深克隆:既復(fù)制基本類型的變量吕朵,也復(fù)制引用類型變量猎醇。

感謝您的閱讀~

轉(zhuǎn)載請注明出處喔:http://www.reibang.com/p/d89b6f77a60f

推薦閱讀

基礎(chǔ)篇:
設(shè)計(jì)模式前篇之——UML類圖必會知識點(diǎn)
設(shè)計(jì)模式前篇之——一起過一下面向?qū)ο蟮母拍?/a>
創(chuàng)建型模式:
簡易理解設(shè)計(jì)模式之:簡單工廠模式——來試試接入支付功能
簡易理解設(shè)計(jì)模式之:工廠方法模式——數(shù)據(jù)存儲例子
簡易理解設(shè)計(jì)模式之:抽象工廠模式——更換數(shù)據(jù)庫例子
簡易理解設(shè)計(jì)模式之:建造者模式——學(xué)習(xí)使用“鏈?zhǔn)秸{(diào)用”
簡易理解設(shè)計(jì)模式之:原型模式——深、淺拷貝的概念
簡易理解設(shè)計(jì)模式之:單例模式——單例模式的幾種常用寫法
結(jié)構(gòu)型模式:
簡易理解設(shè)計(jì)模式之:適配器模式——Android列表視圖控件設(shè)計(jì)方式
簡易理解設(shè)計(jì)模式之:橋接模式——穿衣服經(jīng)典案例2
簡易理解設(shè)計(jì)模式之:組合模式——實(shí)現(xiàn)View中的樹狀結(jié)構(gòu)
簡易理解設(shè)計(jì)模式之:裝飾模式——穿衣服經(jīng)典案例
簡易理解設(shè)計(jì)模式之:外觀模式——第三方SDK的幫助類
簡易理解設(shè)計(jì)模式之:享元模式——五子棋游戲例子
簡易理解設(shè)計(jì)模式之:代理模式——iOS視圖控件設(shè)計(jì)方式
行為型模式:
簡易理解設(shè)計(jì)模式之:策略模式——優(yōu)化一下支付功能
簡易理解設(shè)計(jì)模式之:模板方法模式——Android中的BaseActivity基類
簡易理解設(shè)計(jì)模式之:觀察者模式——監(jiān)聽與回調(diào)
簡易理解設(shè)計(jì)模式之:狀態(tài)模式——優(yōu)化登錄操作
簡易理解設(shè)計(jì)模式之:備忘錄模式——Word文檔的工作原理
簡易理解設(shè)計(jì)模式之:迭代器模式——遍歷對象的好幫手
簡易理解設(shè)計(jì)模式之:命令模式——實(shí)現(xiàn)命令的參數(shù)化配置
簡易理解設(shè)計(jì)模式之:責(zé)任鏈模式——OA中請假流程示例
簡易理解設(shè)計(jì)模式之:中介者模式——多人聊天室例子
簡易理解設(shè)計(jì)模式之:解釋器模式——語言和文法
簡易理解設(shè)計(jì)模式之:訪問者模式——員工考核例子

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末努溃,一起剝皮案震驚了整個(gè)濱河市硫嘶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梧税,老刑警劉巖沦疾,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異第队,居然都是意外死亡哮塞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門凳谦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忆畅,“玉大人,你說我怎么就攤上這事尸执〖铱” “怎么了缓醋?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绊诲。 經(jīng)常有香客問我送粱,道長,這世上最難降的妖魔是什么掂之? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任抗俄,我火速辦了婚禮,結(jié)果婚禮上世舰,老公的妹妹穿的比我還像新娘橄镜。我一直安慰自己,他們只是感情好冯乘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晒夹,像睡著了一般裆馒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丐怯,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天喷好,我揣著相機(jī)與錄音,去河邊找鬼读跷。 笑死梗搅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的效览。 我是一名探鬼主播无切,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丐枉!你這毒婦竟也來了哆键?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤瘦锹,失蹤者是張志新(化名)和其女友劉穎籍嘹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弯院,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辱士,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了听绳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颂碘。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辫红,靈堂內(nèi)的尸體忽然破棺而出凭涂,到底是詐尸還是另有隱情祝辣,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布切油,位于F島的核電站蝙斜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏澎胡。R本人自食惡果不足惜孕荠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望攻谁。 院中可真熱鬧稚伍,春花似錦、人聲如沸戚宦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽受楼。三九已至垦搬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間艳汽,已是汗流浹背猴贰。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留河狐,地道東北人米绕。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像馋艺,于是被迫代替她去往敵國和親栅干。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345