備忘錄模式又叫做快照模式,屬于行為型模式,是指使用一個備忘錄物件來存盤另一個物件內部狀態的快照,備忘錄模式的用以是在不破壞封裝的條件下,將一個物件的狀態捕捉住,并外部化,存盤起來,從而可以在將來合適的時候把這個物件還原到存盤起來的狀態,
開發者對這個模式應該很熟悉,我們使用的開發軟體都會有這樣的備忘錄功能,在編輯時按 Ctrl+Z 組合鍵時能撤銷當前操作,使檔案恢復到之前的狀態;資料庫也有undo、redo的日志記錄功能,如果在一個事務內報錯了,可以回歸到修改之前的資料,
備忘錄模式的UML類圖如下:

由上圖可知備忘錄模式主要涉及到備忘錄(Memento)角色、發起人(Originator)角色和負責人(Caretaker)角色三個角色:
- 發起人(Originator)角色:創建一個含有當前的內部狀態備忘錄物件,使用備忘錄物件存盤其內部狀態
- 備忘錄(Memento)角色:負責保存好記錄,即發起人角色的內部狀態,備忘錄可以根據發起人物件的判斷來決定存盤多少發起人物件的內部狀態
- 負責人(Caretaker)角色:負責保存備忘錄物件,不檢查備忘錄物件的內容,一般使用記錄保存備忘錄物件
游戲角色例子
游戲角色有攻擊力和防御力,在大戰Boss前保存自身的狀態(攻擊力和防御力),當大戰Boss 后攻擊力和防御力下降,從備忘錄物件恢復到大戰前的狀態,
例子的UML類圖:

備忘錄角色:
package com.charon.Memento;
/**
* @className: Memento
* @description: 備忘錄角色
* @author: charon
* @create: 2022-04-05 22:43
*/
public class Memento {
private int vit,def;
public Memento(int vit, int def) {
this.vit = vit;
this.def = def;
}
public Memento() {
}
/**
* Gets the value of vit
*
* @return the value of vit
*/
public int getVit() {
return vit;
}
/**
* Gets the value of def
*
* @return the value of def
*/
public int getDef() {
return def;
}
}
負責人角色:
package com.charon.Memento;
import java.util.ArrayList;
import java.util.List;
/**
* @className: Caretaker
* @description: 負責人角色
* @author: charon
* @create: 2022-04-05 22:50
*/
public class Caretaker {
private Memento memento = new Memento();
/**
* Gets the value of mementos
*
* @return the value of mementos
*/
public Memento getMemento() {
return memento;
}
/**
* Sets the mementos
*
* @param memento memento
*/
public void setMemento(Memento memento) {
this.memento = memento;
}
}
發起人角色:
package com.charon.Memento;
/**
* @className: GameRole
* @description:
* @author: charon
* @create: 2022-04-05 23:01
*/
public class GameRole {
private int vit,def;
public GameRole(int vit, int def) {
this.vit = vit;
this.def = def;
}
/**
* Gets the value of vit
*
* @return the value of vit
*/
public int getVit() {
return vit;
}
/**
* Sets the vit
*
* @param vit vit
*/
public void setVit(int vit) {
this.vit = vit;
}
/**
* Gets the value of def
*
* @return the value of def
*/
public int getDef() {
return def;
}
/**
* Sets the def
*
* @param def def
*/
public void setDef(int def) {
this.def = def;
}
/**
* 創建備忘錄物件
* @return
*/
public Memento createMemento(){
return new Memento(vit,def);
}
/**
* 從備忘錄物件中恢復gameRole的狀態
* @param memento
*/
public void recoverGameRoleFromMemento(Memento memento){
this.vit = memento.getVit();
this.def = memento.getDef();
}
public void display(){
System.out.println("當前游戲角色的攻擊力為:" + this.vit + " ;防御力為:" + this.def);
}
}
測驗:
package com.charon.Memento;
/**
* @className: Client
* @description:
* @author: charon
* @create: 2022-04-04 23:00
*/
public class Client {
public static void main(String[] args) {
// 創建游戲角色
GameRole role = new GameRole(100,100);
System.out.println("大戰前的狀態:");
role.display();
// 保存當前狀態
Caretaker caretaker = new Caretaker();
caretaker.setMemento(role.createMemento());
System.out.println("開始打boss:");
role.setDef(70);
role.setVit(70);
role.display();
System.out.println("大戰后,使用備忘錄物件恢復到戰前");
role.recoverGameRoleFromMemento(caretaker.getMemento());
System.out.println("恢復后的狀態:");
role.display();
}
}
列印:
大戰前的狀態:
當前游戲角色的攻擊力為:100 ;防御力為:100
開始打boss:
當前游戲角色的攻擊力為:70 ;防御力為:70
大戰后,使用備忘錄物件恢復到戰前
恢復后的狀態:
當前游戲角色的攻擊力為:100 ;防御力為:100
備忘錄模式主要的優點如下:
- 提供了一種可以恢復狀態的機制,當用戶需要時能夠比較方便地將資料恢復到某個歷史的狀態,
- 實作了內部狀態的封裝,除了創建它的發起人之外,其他物件都不能夠訪問這些狀態資訊,
- 簡化了發起人類,發起人不需要管理和保存其內部狀態的各個備份,所有狀態資訊都保存在備忘錄中,并由管理者進行管理,這符合單一職責原則,
其主要缺點是:
- 資源消耗大,如果要保存的內部狀態資訊過多或者特別頻繁,將會占用比較大的記憶體資源,
備忘錄模式的應用場景
- 需要保存與恢復資料的場景,如玩游戲時的中間結果的存檔功能,
- 需要提供一個可回滾操作的場景,如 Word、記事本、Photoshop,Eclipse 等軟體在編輯時按 Ctrl+Z 組合鍵,還有資料庫中事務操作,
備忘錄模式與命令模式的關系
如果涉及到某個物件的可撤銷操作的狀態存盤問題,那么僅僅使用備忘錄模式是不夠的,應該考慮使用命令模式,
如果在某個系統中使用命令模式時,需要實作命令的撤銷功能,那么命令模式可以使用備忘錄模式來存盤可撤銷操作的狀態,
本文著作權歸Charon和博客園共有,原創文章,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/456206.html
標籤:設計模式
下一篇:設計模式之備忘錄模式
