簡易理解設計模式之:備忘錄模式——Word文檔的工作原理

介紹:

備忘錄模式屬于行為型模式。它的定義為:在不破壞封閉的前提下,捕獲一個對象的內部狀態(tài),并在該對象之外保存這個狀態(tài)暖眼,這樣以后就可以將該對象恢復到原先保存的狀態(tài)。

類圖:

備忘錄模式UML類圖.png

Originator(發(fā)起人角色):負責創(chuàng)建一個備忘錄Memento纺裁,用以記錄當前時刻它的內部狀態(tài)诫肠,并可以使用備忘錄恢復內部狀態(tài)。Originator可根據需要決定Memento存儲Originator的哪些內部狀態(tài)欺缘。

Memento(備忘錄角色):負責存儲Originator對象的內部狀態(tài)栋豫,并可防止Originator意外的其它對象訪問備忘錄。

Caretaker(管理者角色):負責保存好備忘錄Memento谚殊,不能對備忘錄的內容進行操作丧鸯。

用法:

? 需要保存一個對象在某一時刻的狀態(tài)
? 一個對象不希望外界直接訪問其內部狀態(tài),通過中間對象可以間接訪問其內部狀態(tài)

個人理解:
? 備忘錄模式的應用場景就是存檔備份相關的業(yè)務了嫩絮。如果有需要提供撤銷和恢復操作的需求丛肢,可以考慮使用備忘錄模式围肥,比如:數據庫備份與還原編輯器撤銷與重做摔踱、游戲存檔虐先、Git版本管理等怨愤。

? 關鍵字就是存檔和恢復了派敷,存取的操作可以是存到本地的磁盤或者數據庫,又或者是new一個對象作為緩存保存在內存當中撰洗。一般來說篮愉,備忘錄模式中的存取操作是將對象保存到內存當中去的。

例子:

我們使用Word文檔編輯差导,首先寫完一篇文章试躏,點完保存的操作才能順利保存文本內容,下面我們模擬一下這個邏輯:

需求:模擬Word文檔的業(yè)務

1设褐、普通方法(第一版代碼)

1.1颠蕴、定好架構
首先用逆向思維大概構想這個功能。從使用端的角度來說助析,最后的調用大概是這樣子:

  Word w = new Word();
  w.edit("哈哈哈");
  w.save();
  w.edit("哈哈哈哈123");
  w.restore();

1.2犀被、生成Word類

public class Word {
    private String text;

    /**
     * 編輯文檔
     *
     * @param text
     */
    public void edit(String text) {
        this.text = text;
    }

    /**
     * 保存文檔
     */
    public void save() {
        //將text屬性存到本地或數據庫
    }

    /**
     * 恢復文檔
     */
    public void restore() {
        //從本地或數據庫得到text屬性
    }

    @Override
    public String toString() {
        return "文本內容為:" + text;
    }
}

好簡單,為了將text保存到本地或者數據庫外冀,實現save()restore()方法就可以了寡键。我們的平常在開發(fā)中的做法就是生成多一個數據管理類進行數據的管理。

1.3雪隧、生成WordDB類

public class WordDB {
    private String text;
    private static WordDB mInstance;

    public static WordDB getInstance(){
        if (mInstance == null){
            mInstance = new WordDB();
        }
        return mInstance;
    }

    public String getText() {
        return text;
    }

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

這里簡單用單例模擬一下西轩,負責存取一個文本內容。那在1.2中save()方法和restore()方法的實現如下:

    /**
     * 保存文檔
     */
    public void save() {
        //將text屬性存到本地或數據庫
        WordDB.getInstance().setText(text);
    }

    /**
     * 恢復文檔
     */
    public void restore() {
        //從本地得到text屬性或數據庫
        this.text = WordDB.getInstance().getText();
    }

1.4脑沿、測試與實現

public static void main(String[] args) {
    Word w = new Word();
    w.edit("哈哈哈");
    System.out.println(w.toString());
    w.save();
    System.out.println("=====執(zhí)行保存操作=====");
    w.edit("哈哈哈哈123");
    System.out.println("重新編輯藕畔," + w.toString());
    w.restore();
    System.out.println("=====執(zhí)行恢復操作=====");
    System.out.println("恢復后," + w.toString());
}
文本內容為:哈哈哈
=====執(zhí)行保存操作=====
重新編輯庄拇,文本內容為:哈哈哈哈123
=====執(zhí)行恢復操作=====
恢復后注服,文本內容為:哈哈哈

執(zhí)行save()方法,相當于將text內容插入進了WordDB中去丛忆,而執(zhí)行resotre()就是WordDB中把數據拿回來祠汇。

1.5、分析
這里是我們很常用的做法熄诡,也就是簡單的模擬一下本次存儲功能可很。這種簡單的“存檔”功能并不需要運用到備忘錄模式

2凰浮、使用備忘錄模式優(yōu)化(第二版代碼)

我們讓功能復雜一點點我抠,我們可以隨便獲取某一次的保存的歷史記錄苇本,看看如何實現吧。

歷史記錄1 歷史記錄2 歷史記錄3 歷史記錄4 歷史記錄5 歷史記錄6 歷史記錄7

在第一版的例子中菜拓,我們把數據存檔存到本地磁盤或者是數據庫中瓣窄,相當于點擊了“保存”按鈕。而備忘錄角色的存儲屬于臨時存儲纳鼎,也就是某一個過渡的狀態(tài)俺夕,相當于點擊了“撤銷”“重做”按鈕。

2.1贱鄙、創(chuàng)建備忘錄角色WordMemento類

public class WordMemento {
    private String text;

    public WordMemento(String text) {
        this.text = text;
    }

    public String getText(){
        return text;
    }
}

使用上劝贸,備忘錄角色直接將臨時狀態(tài)的變量保存到內存中。理解上逗宁,這種撤銷和重做的功能并不需要關掉Word后再重新打開映九,也沒必要存到本地磁盤中。

2.2瞎颗、創(chuàng)建管理者角色WordCaretaker

public class WordCaretaker {

    private List<WordMemento> mementos = new ArrayList<>();

    public WordMemento getMemento(int index) {
        return mementos.get(index);
    }

    public void setMemento(WordMemento db) {
        mementos.add(db);
    }

}

歷史記錄當然不止一條件甥,每一次的輸出結果都是有順序的,所以這個用了一個List集合去操作備忘錄角色哼拔。

2.3引有、擴充Word類為WordOriginator
在1.2的例子上,我們擴展一下功能

public class WordOriginator {
    private String text;
    /**
     * 編輯文檔管挟,每編輯完一次做一下保存
     *
     * @param text
     */
    public WordMemento edit(String text) {
        this.text = text;
        return new WordMemento(text);
    }
    /**
     * 恢復操作轿曙,獲取上次的狀態(tài)
     */
    public void restoreMemento(WordMemento m) {
        this.text = m.getText();
    }
    /**
     * 最終保存文檔
     */
    public void save() {
        //將text屬性存到本地或數據庫
        WordDB.getInstance().setText(text);
    }
    /**
     * 重新打開時,恢復文檔
     */
    public void restore() {
        //從本地得到text屬性或數據庫
        this.text = WordDB.getInstance().getText();
    }

    @Override
    public String toString() {
        return "文本內容為:" + text;
    }
}

修改了edit()方法僻孝,在每次編輯的同時导帝,保存到備忘錄(就是跟Word一樣的效果)。再來一個restoreMemento()恢復方法穿铆,獲取某次狀態(tài)的效果您单。

2.4、修改客戶端使用類

public class WordClient {

    private static int index = -1;
    private static WordCaretaker c = new WordCaretaker();

    public static void main(String[] args) {
        WordOriginator word = new WordOriginator();
        edit(word, "今天");
        edit(word, "今天天氣");
        edit(word, "今天天氣真好");
        edit(word, "今天天氣真好荞雏,出去逛逛虐秦!");
        undo(word);
        undo(word);
        redo(word);
        redo(word);
    }

    /**
     * 打開文檔
     */
    public static void open(WordOriginator originator) {
        originator.restore();
    }

    /**
     * 關閉文檔
     */
    public static void close(WordOriginator originator) {
        originator.save();
    }

    /**
     * 編輯文檔
     */
    public static void edit(WordOriginator originator, String text) {
        c.setMemento(originator.edit(text));
        index++;
        System.out.println("編輯操作," + originator.toString());
    }

    /**
     * 撤銷操作
     */
    public static void undo(WordOriginator originator) {
        index--;
        originator.restoreMemento(c.getMemento(index));
        System.out.println("撤銷操作凤优," + originator.toString());
    }

    /**
     * 重做操作
     */
    public static void redo(WordOriginator originator) {
        index++;
        originator.restoreMemento(c.getMemento(index));
        System.out.println("重做操作悦陋," + originator.toString());
    }


}


    /**
     * 打開文檔
     */
    public static void open(WordOriginator originator){
        originator.restore();
    }

    /**
     * 關閉文檔
     */
    public static void close(WordOriginator originator){
        originator.save();
    }

    /**
     * 編輯文檔
     */
    public static void edit(WordOriginator originator,String text){
        c.setMemento(originator.edit(text));
        index++;
    }

    /**
     * 撤銷操作
     */
    public static void undo(WordOriginator originator){
        index--;
        originator.restoreMemento(c.getMemento(index));
    }

    /**
     * 重做操作
     */
    public static void redo(WordOriginator originator){
        index++;
        originator.restoreMemento(c.getMemento(index));
    }
}
編輯操作,文本內容為:今天
編輯操作筑辨,文本內容為:今天天氣
編輯操作俺驶,文本內容為:今天天氣真好
編輯操作,文本內容為:今天天氣真好棍辕,出去逛逛暮现!
撤銷操作还绘,文本內容為:今天天氣真好
撤銷操作,文本內容為:今天天氣
重做操作栖袋,文本內容為:今天天氣真好
重做操作拍顷,文本內容為:今天天氣真好,出去逛逛塘幅!

總結:

此模式結構不復雜昔案,簡單來說就是備忘錄角色負責緩存數據,管理者角色負責存取備忘錄晌块,發(fā)起人角色負責將數據傳給備忘錄和從備忘錄中拿數據爱沟。很明顯帅霜,資源過多需要占用大量的存儲空間匆背,資源有限的情況下這個模式要慎重使用。

感謝您的閱讀~

轉載請注明出處喔:http://www.reibang.com/p/b7733f12d6a3

推薦閱讀

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末钝尸,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子搂根,更是在濱河造成了極大的恐慌珍促,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剩愧,死亡現場離奇詭異猪叙,居然都是意外死亡,警方通過查閱死者的電腦和手機仁卷,發(fā)現死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門穴翩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锦积,你說我怎么就攤上這事芒帕。” “怎么了丰介?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵背蟆,是天一觀的道長。 經常有香客問我哮幢,道長带膀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任橙垢,我火速辦了婚禮垛叨,結果婚禮上,老公的妹妹穿的比我還像新娘钢悲。我一直安慰自己点额,他們只是感情好舔株,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著还棱,像睡著了一般载慈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上珍手,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天办铡,我揣著相機與錄音,去河邊找鬼琳要。 笑死寡具,一個胖子當著我的面吹牛,可吹牛的內容都是我干的稚补。 我是一名探鬼主播童叠,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼课幕!你這毒婦竟也來了厦坛?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤乍惊,失蹤者是張志新(化名)和其女友劉穎杜秸,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體润绎,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡撬碟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了莉撇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呢蛤。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖稼钩,靈堂內的尸體忽然破棺而出顾稀,到底是詐尸還是另有隱情,我是刑警寧澤坝撑,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布静秆,位于F島的核電站,受9級特大地震影響巡李,放射性物質發(fā)生泄漏抚笔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一侨拦、第九天 我趴在偏房一處隱蔽的房頂上張望殊橙。 院中可真熱鬧,春花似錦、人聲如沸膨蛮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敞葛。三九已至誉察,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惹谐,已是汗流浹背持偏。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留氨肌,地道東北人鸿秆。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像怎囚,于是被迫代替她去往敵國和親卿叽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345