介紹:
備忘錄模式屬于行為型模式。它的定義為:在不破壞封閉的前提下,捕獲一個對象的內部狀態(tài),并在該對象之外保存這個狀態(tài)暖眼,這樣以后就可以將該對象恢復到原先保存的狀態(tài)。
類圖:
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ā)起人角色負責將數據傳給備忘錄和從備忘錄中拿數據爱沟。很明顯帅霜,資源過多需要占用大量的存儲空間匆背,資源有限的情況下這個模式要慎重使用。
感謝您的閱讀~
推薦閱讀
基礎篇:
設計模式前篇之——UML類圖必會知識點
設計模式前篇之——一起過一下面向對象的概念
創(chuàng)建型模式:
簡易理解設計模式之:簡單工廠模式——來試試接入支付功能
簡易理解設計模式之:工廠方法模式——數據存儲例子
簡易理解設計模式之:抽象工廠模式——更換數據庫例子
簡易理解設計模式之:建造者模式——學習使用“鏈式調用”
簡易理解設計模式之:原型模式——深身冀、淺拷貝的概念
簡易理解設計模式之:單例模式——單例模式的幾種常用寫法
結構型模式:
簡易理解設計模式之:適配器模式——Android列表視圖控件設計方式
簡易理解設計模式之:橋接模式——穿衣服經典案例2
簡易理解設計模式之:組合模式——實現View中的樹狀結構
簡易理解設計模式之:裝飾模式——穿衣服經典案例
簡易理解設計模式之:外觀模式——第三方SDK的幫助類
簡易理解設計模式之:享元模式——五子棋游戲例子
簡易理解設計模式之:代理模式——iOS視圖控件設計方式
行為型模式:
簡易理解設計模式之:策略模式——優(yōu)化一下支付功能
簡易理解設計模式之:模板方法模式——Android中的BaseActivity基類
簡易理解設計模式之:觀察者模式——監(jiān)聽與回調
簡易理解設計模式之:狀態(tài)模式——優(yōu)化登錄操作
簡易理解設計模式之:備忘錄模式——Word文檔的工作原理
簡易理解設計模式之:迭代器模式——遍歷對象的好幫手
簡易理解設計模式之:命令模式——實現命令的參數化配置
簡易理解設計模式之:責任鏈模式——OA中請假流程示例
簡易理解設計模式之:中介者模式——多人聊天室例子
簡易理解設計模式之:解釋器模式——語言和文法
簡易理解設計模式之:訪問者模式——員工考核例子