成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

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

roland_reed / 570人閱讀

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

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

概述

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

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

案例

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

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

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

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

白箱實現(xiàn)

角色組成

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

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

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

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

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

1.創(chuàng)建一個備忘錄角色備忘錄,內(nèi)部定義了一個變量用來區(qū)分當(dāng)前對象狀態(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)建一個原發(fā)器對象Originator,定義了創(chuàng)建備忘錄對象和回滾的對象

public class Originator {

    private String state;

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

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

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

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

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

public class Caretaker {
    /**
     * 備忘錄對象
     */
    private Memento memento;

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

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

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

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());
        // 存儲內(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.運行結(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
黑箱實現(xiàn)

角色組成

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

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

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

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

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

1.備忘錄窄接口

public interface MementoIF {
}

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

public class Originator {

    private String state;

    public String getState() {
        return state;
    }

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

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

    /**
     * 發(fā)起人恢復(fù)到備忘錄對象記錄的狀態(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,管理備忘錄對象的

public class Caretaker {
    /**
     * 備忘錄對象
     */
    private MementoIF memento;

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

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

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

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());

        // 存儲內(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.運行結(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ū)別就是外部能不能訪問備忘錄的狀態(tài),備忘錄角色具有安全等級;這里關(guān)于備忘錄角色 -> 白箱實現(xiàn)利用的寬接口,黑箱模式利用的窄接口;

多重檢查點

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

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

自述歷史

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

總結(jié)

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

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

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

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

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

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

優(yōu)點

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

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

缺點

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

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

適用場景

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

提供一個可回滾的操作。

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

說點什么

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

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

個人QQ:1837307557

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

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

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/70734.html

相關(guān)文章

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

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

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

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

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

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

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

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

    dingding199389 評論0 收藏0

發(fā)表評論

0條評論

roland_reed

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<