設(shè)計(jì)模式系列-原型模式畦木,備忘錄模式

原型模式

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

    public class PrototypeClass implements Cloneable{

         //覆寫父類Object方法
         @Override
         public PrototypeClass clone(){
                 PrototypeClass prototypeClass = null;
                 try {
                        prototypeClass = (PrototypeClass)super.clone();
                 } catch (CloneNotSupportedException e) {
                        //異常處理
                 }
                 return prototypeClass;
         }
    }

原型模式已經(jīng)與Java融為一體,大家可以隨手拿來使用孔轴。

資源性能優(yōu)化場景:

類初始化需要非常繁瑣的數(shù)據(jù)準(zhǔn)備剃法,需要消化非常多的資源,這個(gè)資源包括數(shù)據(jù)路鹰、硬件資源等贷洲。

一個(gè)對象多個(gè)修改者的場景:

一個(gè)對象需要提供給其他對象訪問,而且各個(gè)調(diào)用者可能都需要修改其值時(shí)悍引,可以考慮使用原型模式拷貝多個(gè)對象供調(diào)用者使用恩脂。

注意:

clone時(shí)構(gòu)造函數(shù)不會被執(zhí)行,Object類的clone方法的原理是從內(nèi)存中(具體地說就是堆內(nèi)存)以二進(jìn)制流的方式進(jìn)行拷貝趣斤,重新分配一個(gè)內(nèi)存塊俩块,那構(gòu)造函數(shù)沒有被執(zhí)行也是非常正常的了。

淺拷貝和深拷貝:

關(guān)于淺拷貝:

    public class Thing implements Cloneable{
         //定義一個(gè)私有變量
         private ArrayList arrayList = new ArrayList();

         @Override
         public Thing clone(){
                 Thing thing=null;
                 try {
                        thing = (Thing)super.clone();
                 } catch (CloneNotSupportedException e) {
                        e.printStackTrace();
                 }
                 return thing;
         }
         public void setValue(String value){
                 this.arrayList.add(value);
         }
         public ArrayList getValue(){
                 return this.arrayList;
         }
    }

Object類提供的方法clone只是拷貝本對象浓领,其對象內(nèi)部的數(shù)組玉凯、引用對象等都不拷貝,還是指向原生對象的內(nèi)部元素地址联贩,這種拷貝就叫做淺拷貝漫仆。

原始類型+裝箱類型+String 會被拷貝,但其他的內(nèi)部成員對象和數(shù)組不會拷貝泪幌,只會拷貝其引用盲厌。

關(guān)于深拷貝:

    public class Thing implements Cloneable{
         //定義一個(gè)私有變量
         private ArrayList arrayList = new ArrayList();
         @Override
         public Thing clone(){
                 Thing thing=null;
                 try {
                        thing = (Thing)super.clone();
                        thing.arrayList = (ArrayList)this.arrayList.clone();
                 } catch (CloneNotSupportedException e) {
                        e.printStackTrace();
                 }
                 return thing;
         }
    }

注意這里數(shù)組與ArrayList等clone,只會拷貝內(nèi)部元素的引用數(shù)組祸泪,并不會深拷貝數(shù)組內(nèi)部的元素吗浩。

關(guān)于一些其他的拷貝的姿勢:

1.序列化(List深拷貝)

    public static List deepCopy(List src) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        List dest = (List) in.readObject();
        return dest;
    }

2.System.arraycopy(數(shù)組的淺拷貝)

這個(gè)方法不是用java語言寫的,而是底層用c或者c++實(shí)現(xiàn)的没隘,因而速度會比較快懂扼。但是是淺拷貝

3.Arrays.copyOf(數(shù)組的淺拷貝)

調(diào)用的是System.arraycopy,如ArrayList的clone方法調(diào)用的就是Arrays.copyOf。

備忘錄模式

定義:在不破壞封裝性的前提下阀湿,捕獲一個(gè)對象的內(nèi)部狀態(tài)赶熟,并在該對象之外保存這個(gè)狀態(tài)。這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)陷嘴。

角色:

發(fā)起人角色:記錄當(dāng)前時(shí)刻的內(nèi)部狀態(tài)映砖,負(fù)責(zé)定義哪些屬于備份范圍的狀態(tài),負(fù)責(zé)創(chuàng)建和恢復(fù)備忘錄數(shù)據(jù)罩旋。

備忘錄角色:負(fù)責(zé)存儲發(fā)起人對象的內(nèi)部狀態(tài)啊央,在需要的時(shí)候提供發(fā)起人需要的內(nèi)部狀態(tài)眶诈。

Caretaker備忘錄管理員角色:對備忘錄進(jìn)行管理涨醋、保存和提供備忘錄。

    //發(fā)起人角色
    public class Originator {
         //內(nèi)部狀態(tài)
         private String state = "";

         public String getState() {
                 return state;
         }
         public void setState(String state) {
                 this.state = state;
         }
         //創(chuàng)建一個(gè)備忘錄
         public Memento createMemento(){
                 return new Memento(this.state);
         }
         //恢復(fù)一個(gè)備忘錄
         public void restoreMemento(Memento _memento){
                 this.setState(_memento.getState());
         }
    }

    //備忘錄角色
    public class Memento {
         //發(fā)起人的內(nèi)部狀態(tài)
         private String state = "";
         //構(gòu)造函數(shù)傳遞參數(shù)
         public Memento(String _state){
                 this.state = _state;
         }
         public String getState() {
                 return state;
         }
         public void setState(String state) {
                 this.state = state;
         }
    }

    //備忘錄管理員角色
    public class Caretaker {
         //備忘錄對象
         private Memento memento;
         public Memento getMemento() {
                 return memento;
         }
         public void setMemento(Memento memento) {
                 this.memento = memento;
         }
    }

    public class Client {
         public static void main(String[] args) {
                 //定義出發(fā)起人
                 Originator originator = new Originator();
                 //定義出備忘錄管理員
                 Caretaker caretaker = new Caretaker();
                 //創(chuàng)建一個(gè)備忘錄
                 caretaker.setMemento(originator.createMemento());
                 //恢復(fù)一個(gè)備忘錄
                 originator.restoreMemento(caretaker.getMemento());
         }
    }

備忘錄模式變種:

1.clone 方式的備忘錄(發(fā)起者與備忘錄融合)

    //發(fā)起者與備忘錄融合
    public class Originator implements Cloneable{
         //內(nèi)部狀態(tài)
         private String state = "";

         public String getState() {
                 return state;
         }
         public void setState(String state) {
                 this.state = state;
         }
         //創(chuàng)建一個(gè)備忘錄
         public Originator createMemento(){
                 return this.clone();
         }
         //恢復(fù)一個(gè)備忘錄
         public void restoreMemento(Originator _originator){
                 this.setState(_originator.getState());
         }
         //克隆當(dāng)前對象
         @Override
         protected Originator clone(){
                 try {
                         return (Originator)super.clone();
                 } catch (CloneNotSupportedException e) {
                         e.printStackTrace();
                 }
                 return null;
         }
    }

    public class Caretaker {
         //發(fā)起人對象
         private Originator originator;
         public Originator getOriginator() {
                 return originator;
         }
         public void setOriginator(Originator originator) {
                 this.originator = originator;
         }
    }

1.clone 方式的備忘錄(發(fā)起者與備忘錄和管理者 融合)

    public class Originator implements Cloneable{
         private Originator backup;
         //內(nèi)部狀態(tài)
         private String state = "";
         public String getState() {
                 return state;
         }
         public void setState(String state) {
                 this.state = state;
         }
         //創(chuàng)建一個(gè)備忘錄
         public void createMemento(){
                 this.backup = this.clone();
         }
         //恢復(fù)一個(gè)備忘錄
         public void restoreMemento(){
                 //在進(jìn)行恢復(fù)前應(yīng)該進(jìn)行斷言逝撬,防止空指針
                 this.setState(this.backup.getState());
         }
         //克隆當(dāng)前對象
         @Override
         protected Originator clone(){
                 try {
                         return (Originator)super.clone();
                 } catch (CloneNotSupportedException e) {
                         e.printStackTrace();
                 }
                 return null;
         }
    }

提問浴骂?在該對象之外保存這個(gè)狀態(tài),是否矛盾宪潮?

現(xiàn)在我們來考慮一下原型模式深拷貝和淺拷貝的問題溯警,在復(fù)雜的場景下它會讓你的程序邏輯異常混亂狡相,出現(xiàn)錯(cuò)誤也很難跟蹤梯轻。因此Clone方式的備忘錄模式適用于較簡單的場景。

多狀態(tài)的時(shí)候需要怎么寫尽棕?

    public class Caretaker {
         //容納備忘錄的容器
         private ArrayMap<String,Memento> memMap = new ArrayMap<String,Memento>();
         public Memento getMemento(String idx) {
                 return memMap.get(idx);
         }
         public void setMemento(String idx,Memento memento) {
                 this.memMap.put(idx, memento);
         }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喳挑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子滔悉,更是在濱河造成了極大的恐慌伊诵,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件回官,死亡現(xiàn)場離奇詭異曹宴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)歉提,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門笛坦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苔巨,你說我怎么就攤上這事版扩。” “怎么了恋拷?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵资厉,是天一觀的道長。 經(jīng)常有香客問我蔬顾,道長宴偿,這世上最難降的妖魔是什么湘捎? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮窄刘,結(jié)果婚禮上窥妇,老公的妹妹穿的比我還像新娘。我一直安慰自己娩践,他們只是感情好活翩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著翻伺,像睡著了一般材泄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吨岭,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天拉宗,我揣著相機(jī)與錄音,去河邊找鬼辣辫。 笑死旦事,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的急灭。 我是一名探鬼主播姐浮,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼葬馋!你這毒婦竟也來了卖鲤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤点楼,失蹤者是張志新(化名)和其女友劉穎扫尖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掠廓,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡换怖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蟀瞧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沉颂。...
    茶點(diǎn)故事閱讀 38,724評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖悦污,靈堂內(nèi)的尸體忽然破棺而出铸屉,到底是詐尸還是另有隱情,我是刑警寧澤切端,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布彻坛,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏昌屉。R本人自食惡果不足惜钙蒙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望间驮。 院中可真熱鬧躬厌,春花似錦、人聲如沸竞帽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屹篓。三九已至疙渣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抱虐,已是汗流浹背昌阿。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工饥脑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恳邀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓灶轰,卻偏偏與公主長得像谣沸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子笋颤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容