成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

一起學(xué)設(shè)計(jì)模式 - 備忘錄模式

roland_reed / 530人閱讀

摘要:備忘錄模式常常與命令模式和迭代子模式一同使用。自述歷史所謂自述歷史模式實(shí)際上就是備忘錄模式的一個(gè)變種。在備忘錄模式中,發(fā)起人角色負(fù)責(zé)人角色和備忘錄角色都是獨(dú)立的角色。

備忘錄模式(Memento Pattern)屬于行為型模式的一種,在不破壞封裝特性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣就可以將該對(duì)象恢復(fù)到原先保存的狀態(tài)。

概述

備忘錄模式又叫做快照模式(Snapshot Pattern),一個(gè)用來(lái)存儲(chǔ)另外一個(gè)對(duì)象內(nèi)部狀態(tài)的快照的對(duì)象。

備忘錄模式的用意是在不破壞封裝的條件下,將一個(gè)對(duì)象的狀態(tài)捕捉(Capture)住,并外部化,存儲(chǔ)起來(lái),從而可以在將來(lái)合適的時(shí)候把這個(gè)對(duì)象還原到存儲(chǔ)起來(lái)的狀態(tài)。備忘錄模式常常與命令模式和迭代子模式一同使用。

案例

前言:備忘錄模式按照備忘錄角色的形態(tài)不同,分為白箱實(shí)現(xiàn)與黑箱實(shí)現(xiàn),兩種模式與備忘錄角色提供的接口模式有關(guān);

引入兩個(gè)定義,備忘錄有兩個(gè)等效的接口:

窄接口:負(fù)責(zé)人(Caretaker)對(duì)象(和其他除發(fā)起人對(duì)象之外的任何對(duì)象)看到的是備忘錄的窄接口(narrow interface),這個(gè)窄接口只允許它把備忘錄對(duì)象傳給其他的對(duì)象。

寬接口:與負(fù)責(zé)人對(duì)象看到的窄接口相反的是,發(fā)起人對(duì)象可以看到一個(gè)寬接口(wide interface),這個(gè)寬接口允許它讀取所有的數(shù)據(jù),以便根據(jù)這些數(shù)據(jù)恢復(fù)這個(gè)發(fā)起人對(duì)象的內(nèi)部狀態(tài)。

白箱實(shí)現(xiàn)

角色組成

Memento(備忘錄角色): 負(fù)責(zé)存儲(chǔ)原發(fā)器對(duì)象的內(nèi)部狀態(tài),但是具體需要存儲(chǔ)哪些數(shù)據(jù)是由原發(fā)器對(duì)象來(lái)決定的,在需要的時(shí)候提供原發(fā)器需要的內(nèi)部狀態(tài)。PS:這里可以存儲(chǔ)狀態(tài)。

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

Caretaker(備忘錄負(fù)責(zé)人(管理者)角色): 對(duì)備忘錄對(duì)象進(jìn)行管理,但是不能對(duì)備忘錄對(duì)象的內(nèi)容進(jìn)行操作或檢查。

備忘錄角色對(duì)任何對(duì)象都提供公共的訪問(wèn),內(nèi)部所存儲(chǔ)的狀態(tài)對(duì)對(duì)象公開(kāi),即為白箱實(shí)現(xiàn)。白箱實(shí)現(xiàn)發(fā)起人和負(fù)責(zé)人提供相同接口,使得負(fù)責(zé)人可以訪問(wèn)備忘錄全部?jī)?nèi)容,并不安全。白箱實(shí)現(xiàn)對(duì)備忘錄內(nèi)容的保護(hù)靠的是程序員的自律,實(shí)現(xiàn)也很簡(jiǎn)單。

UML結(jié)構(gòu)圖

1.創(chuàng)建一個(gè)備忘錄角色備忘錄,內(nèi)部定義了一個(gè)變量用來(lái)區(qū)分當(dāng)前對(duì)象狀態(tài)

public class Memento {
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return this.state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

2.接著創(chuàng)建一個(gè)原發(fā)器對(duì)象Originator,定義了創(chuàng)建備忘錄對(duì)象和回滾的對(duì)象

public class Originator {

    private String state;

    public String getState() {
        return this.state;
    }

    public void setState(String state) {
        this.state = state;
    }

    /**
     * 創(chuàng)建對(duì)象
     *
     * @return 備忘錄對(duì)象
     */
    public Memento createMemento() {
        return new Memento(state);
    }

    /**
     * 從備忘錄中恢復(fù)
     *
     * @param memento 恢復(fù)的對(duì)象
     */
    public void restoreMemento(Memento memento) {
        this.state = memento.getState();
    }
}

3.創(chuàng)建備忘錄管理者Caretaker,顧名思義就是來(lái)管理備忘錄對(duì)象的

public class Caretaker {
    /**
     * 備忘錄對(duì)象
     */
    private Memento memento;

    /**
     * 獲取備忘錄
     *
     * @return 備忘錄對(duì)象
     */
    public Memento retrieveMemento() {
        return this.memento;
    }

    /**
     * 存儲(chǔ)備忘錄對(duì)象
     */
    public void saveMemento(Memento memento) {
        this.memento = memento;
    }
}

4.創(chuàng)建測(cè)試類

public class Client {

    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("狀態(tài)A");
        System.out.println("當(dāng)前狀態(tài):" + originator.getState());
        // 存儲(chǔ)內(nèi)部狀態(tài)
        caretaker.saveMemento(originator.createMemento());
        System.out.println("存檔");

        // 改變狀態(tài)
        originator.setState("狀態(tài)B");
        System.out.println("當(dāng)前狀態(tài):" + originator.getState());

        // 改變狀態(tài)
        originator.setState("狀態(tài)C");
        System.out.println("當(dāng)前狀態(tài):" + originator.getState());
        // 恢復(fù)狀態(tài)
        originator.restoreMemento(caretaker.retrieveMemento());
        System.out.println("讀檔");

        System.out.println("恢復(fù)后狀態(tài):" + originator.getState());
    }
}

5.運(yùn)行結(jié)果

當(dāng)前狀態(tài):狀態(tài)A
存檔
當(dāng)前狀態(tài):狀態(tài)B
當(dāng)前狀態(tài):狀態(tài)C
讀檔
恢復(fù)后狀態(tài):狀態(tài)A
黑箱實(shí)現(xiàn)

角色組成

MementoIF(備忘錄角色): 空接口,不作任何實(shí)現(xiàn)。

Originator(發(fā)起人(原發(fā)器)角色): 記錄當(dāng)前時(shí)刻的內(nèi)部狀態(tài),負(fù)責(zé)定義哪些屬于備份范圍的狀態(tài),負(fù)責(zé)創(chuàng)建和恢復(fù)備忘錄數(shù)據(jù)。這里Memento做為原發(fā)器的私有內(nèi)部類,來(lái)存儲(chǔ)備忘錄。備忘錄只能由原發(fā)器對(duì)象來(lái)訪問(wèn)它內(nèi)部的數(shù)據(jù),原發(fā)器外部的對(duì)象不應(yīng)該能訪問(wèn)到備忘錄對(duì)象的內(nèi)部數(shù)據(jù)。

Caretaker(備忘錄負(fù)責(zé)人(管理者)角色): 對(duì)備忘錄對(duì)象進(jìn)行管理,但是不能對(duì)備忘錄對(duì)象的內(nèi)容進(jìn)行操作或檢查。

Memento 對(duì)象給 Originator 角色對(duì)象提供一個(gè)寬接口,而為其他對(duì)象提供一個(gè)窄接口,即為黑箱實(shí)現(xiàn)。

UML結(jié)構(gòu)圖

1.備忘錄窄接口

public interface MementoIF {
}

2.接著創(chuàng)建一個(gè)原發(fā)器對(duì)象Originator,其中定義了一個(gè)私有化的內(nèi)部類Memento實(shí)現(xiàn)了MementoIF接口,只有當(dāng)前對(duì)象能訪問(wèn)

public class Originator {

    private String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    /**
     * 創(chuàng)建一個(gè)新的備忘錄對(duì)象
     */
    public MementoIF createMemento() {
        return new Memento(state);
    }

    /**
     * 發(fā)起人恢復(fù)到備忘錄對(duì)象記錄的狀態(tài)
     */
    public void restoreMemento(MementoIF memento) {
        this.setState(((Memento) memento).getState());
    }

    private class Memento implements MementoIF {

        private String state;

        private Memento(String state) {
            this.state = state;
        }

        private String getState() {
            return state;
        }

        private void setState(String state) {
            this.state = state;
        }
    }
}

3.創(chuàng)建備忘錄管理者Caretaker,管理備忘錄對(duì)象的

public class Caretaker {
    /**
     * 備忘錄對(duì)象
     */
    private MementoIF memento;

    /**
     * 獲取備忘錄對(duì)象
     */
    public MementoIF retrieveMemento() {
        return memento;
    }

    /**
     * 保存?zhèn)渫泴?duì)象
     */
    public void saveMemento(MementoIF memento) {
        this.memento = memento;
    }
}

4.創(chuàng)建測(cè)試類

public class Client {

    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.setState("狀態(tài)A");
        System.out.println("當(dāng)前狀態(tài):" + originator.getState());
        // 改變狀態(tài)
        originator.setState("狀態(tài)B");
        System.out.println("當(dāng)前狀態(tài):" + originator.getState());

        // 存儲(chǔ)內(nèi)部狀態(tài)
        caretaker.saveMemento(originator.createMemento());
        System.out.println("存檔");
        
        // 改變狀態(tài)
        originator.setState("狀態(tài)C");
        System.out.println("當(dāng)前狀態(tài):" + originator.getState());
        // 恢復(fù)狀態(tài)
        originator.restoreMemento(caretaker.retrieveMemento());
        System.out.println("讀檔");

        System.out.println("恢復(fù)后狀態(tài):" + originator.getState());
    }
}

5.運(yùn)行結(jié)果

當(dāng)前狀態(tài):狀態(tài)A
當(dāng)前狀態(tài):狀態(tài)B
存檔
當(dāng)前狀態(tài):狀態(tài)C
讀檔
恢復(fù)后狀態(tài):狀態(tài)B

兩者的代碼結(jié)構(gòu)是比較類似的,本質(zhì)區(qū)別就是外部能不能訪問(wèn)備忘錄的狀態(tài),備忘錄角色具有安全等級(jí);這里關(guān)于備忘錄角色 -> 白箱實(shí)現(xiàn)利用的寬接口,黑箱模式利用的窄接口;

多重檢查點(diǎn)

前面所給出的白箱和黑箱的示意性實(shí)現(xiàn)都是只存儲(chǔ)一個(gè)狀態(tài)的簡(jiǎn)單實(shí)現(xiàn),也可以叫做只有一個(gè)檢查點(diǎn)。常見(jiàn)的系統(tǒng)往往需要存儲(chǔ)不止一個(gè)狀態(tài),而是需要存儲(chǔ)多個(gè)狀態(tài),或者叫做有多個(gè)檢查點(diǎn)。 這種情況只需要使用有序隊(duì)列方式可以很容易達(dá)到多重檢查點(diǎn)

備忘錄模式可以將發(fā)起人對(duì)象的狀態(tài)存儲(chǔ)到備忘錄對(duì)象里面,備忘錄模式可以將發(fā)起人對(duì)象恢復(fù)到備忘錄對(duì)象所存儲(chǔ)的某一個(gè)檢查點(diǎn)上。

自述歷史

所謂自述歷史模式(History-On-Self Pattern)實(shí)際上就是備忘錄模式的一個(gè)變種。在備忘錄模式中,發(fā)起人(Originator)角色、負(fù)責(zé)人(Caretaker)角色和備忘錄 (Memento)角色都是獨(dú)立的角色。雖然在實(shí)現(xiàn)上備忘錄類可以成為發(fā)起人類的內(nèi)部成員類,但是備忘錄類仍然保持作為一個(gè)角色的獨(dú)立意義。在自述歷史模式里面,發(fā)起人角色自己兼任負(fù)責(zé)人角色。
  
完整代碼在GIT項(xiàng)目中

總結(jié)

關(guān)于使用備忘錄的潛在代價(jià):

  標(biāo)準(zhǔn)的備忘錄模式的實(shí)現(xiàn)機(jī)制是依靠緩存來(lái)實(shí)現(xiàn)的,因此,當(dāng)需要備忘的數(shù)據(jù)量較大時(shí),或者是存儲(chǔ)的備忘錄對(duì)象數(shù)據(jù)量不大但是數(shù)量很多的時(shí)候,或者是用戶很頻繁的創(chuàng)建備忘錄對(duì)象的時(shí)候,這些都會(huì)導(dǎo)致非常大的開(kāi)銷(xiāo)。

  因此在使用備忘錄模式的時(shí)候,一定要好好思考應(yīng)用的環(huán)境,如果使用的代價(jià)太高,就不要選用備忘錄模式,可以采用其它的替代方案。

關(guān)于增量存儲(chǔ):

  如果需要頻繁的創(chuàng)建備忘錄對(duì)象,而且創(chuàng)建和應(yīng)用備忘錄對(duì)象來(lái)恢復(fù)狀態(tài)的順序是可控的,那么可以讓備忘錄進(jìn)行增量存儲(chǔ),也就是備忘錄可以僅僅存儲(chǔ)原發(fā)器內(nèi)部相對(duì)于上一次存儲(chǔ)狀態(tài)后的增量改變。

  比如:在命令模式實(shí)現(xiàn)可撤銷(xiāo)命令的實(shí)現(xiàn)中,就可以使用備忘錄來(lái)保存每個(gè)命令對(duì)應(yīng)的狀態(tài),然后在撤銷(xiāo)命令的時(shí)候,使用備忘錄來(lái)恢復(fù)這些狀態(tài)。由于命令的歷史列表是按照命令操作的順序來(lái)存放的,也是按照這個(gè)歷史列表來(lái)進(jìn)行取消和重做的,因此順序是可控的。那么這種情況,還可以讓備忘錄對(duì)象只存儲(chǔ)一個(gè)命令所產(chǎn)生的增量改變而不是它所影響的每一個(gè)對(duì)象的完整狀態(tài)。

優(yōu)點(diǎn)

給用戶提供了一種可以恢復(fù)狀態(tài)的機(jī)制,可以使用戶能夠比較方便地回到某個(gè)歷史的狀態(tài)。

實(shí)現(xiàn)了信息的封裝,使得用戶不需要關(guān)心狀態(tài)的保存細(xì)節(jié)。

缺點(diǎn)

消耗資源。如果類的成員變量過(guò)多,勢(shì)必會(huì)占用比較大的資源,而且每一次保存都會(huì)消耗一定的內(nèi)存。

由于備份的信息是由發(fā)起人自己提供的,所以管理者無(wú)法預(yù)知備份的信息的大小,所以在客戶端使用時(shí),可能一個(gè)操作占用了很大的內(nèi)存,但客戶端并不知曉。

適用場(chǎng)景

需要保存/恢復(fù)數(shù)據(jù)的相關(guān)狀態(tài)場(chǎng)景。

提供一個(gè)可回滾的操作。

備忘錄模式在很多軟件的使用過(guò)程中普遍存在,但是在應(yīng)用軟件開(kāi)發(fā)中,它的使用頻率并不太高;

說(shuō)點(diǎn)什么

參考文獻(xiàn):http://www.cnblogs.com/JsonShare/p/7283972.html

全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter16/battcn-memento

個(gè)人QQ:1837307557

battcn開(kāi)源群(適合新手):391619659

微信公眾號(hào):battcn(歡迎調(diào)戲)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70734.html

相關(guān)文章

  • 練就Java24章真經(jīng)—你所不知道的工廠方法

    摘要:用專業(yè)的話來(lái)講設(shè)計(jì)模式是一套被反復(fù)使用多數(shù)人知曉的經(jīng)過(guò)分類編目的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)創(chuàng)建型模式,共五種工廠方法模式抽象工廠模式單例模式建造者模式原型模式。工廠方法模式的擴(kuò)展性非常優(yōu)秀。工廠方法模式是典型的解耦框架。 前言 最近一直在Java方向奮斗《終于,我還是下決心學(xué)Java后臺(tái)了》,今天抽空開(kāi)始學(xué)習(xí)Java的設(shè)計(jì)模式了。計(jì)劃有時(shí)間就去學(xué)習(xí),你這么有時(shí)間,還不來(lái)一起上車(chē)嗎? 之所以要學(xué)...

    Chiclaim 評(píng)論0 收藏0
  • 【Vue原理】Vue源碼閱讀總結(jié)大會(huì) - 序

    摘要:扎實(shí)基礎(chǔ)幸好自己之前花了大力氣去給自己打基礎(chǔ),讓自己現(xiàn)在的基礎(chǔ)還算不錯(cuò)。 寫(xiě)文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺(jué)得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Vue源碼閱讀總結(jié)大會(huì) - 序 閱讀源碼是需...

    Edison 評(píng)論0 收藏0
  • 性能優(yōu)化

    摘要:如果你的運(yùn)行緩慢,你可以考慮是否能優(yōu)化請(qǐng)求,減少對(duì)的操作,盡量少的操,或者犧牲其它的來(lái)?yè)Q取性能。在認(rèn)識(shí)描述這些核心元素的過(guò)程中,我們也會(huì)分享一些當(dāng)我們構(gòu)建的時(shí)候遵守的一些經(jīng)驗(yàn)規(guī)則,一個(gè)應(yīng)用應(yīng)該保持健壯和高性能來(lái)維持競(jìng)爭(zhēng)力。 一個(gè)開(kāi)源的前端錯(cuò)誤收集工具 frontend-tracker,你值得收藏~ 蒲公英團(tuán)隊(duì)最近開(kāi)發(fā)了一款前端錯(cuò)誤收集工具,名叫 frontend-tracker ,這款...

    liangzai_cool 評(píng)論0 收藏0
  • 設(shè)計(jì)模式在jdk中的應(yīng)用

    摘要:本文只是尋找設(shè)計(jì)模式在中的應(yīng)用。來(lái)補(bǔ)全這一塊工廠模式中的應(yīng)用包線程池解釋和代碼線程池中有線程創(chuàng)建工廠。狀態(tài)模式中的應(yīng)用解釋和代碼根據(jù)一個(gè)指針的狀態(tài)而改變自己的行為適配器模式中的應(yīng)用解釋和代碼將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。 前言 最近重學(xué)設(shè)計(jì)模式,而且還有很多源碼要看。所以就想一舉兩得。從源碼中尋找設(shè)計(jì)模式。順便還可以看看源碼。。。本文只是尋找設(shè)計(jì)模式在java中的應(yīng)用。優(yōu)...

    dingding199389 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<