定義
備忘錄模式(Memento Pattern):在不破壞封裝的前提下捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,這樣可以在以後將對象恢復到原先保存的裝填。
結構
- Originator(原發器):原發器是一個普通類,它通過創建一個備忘錄來存儲當前內部狀態,也可以使用備忘錄來恢復其內部狀態,一般將系統中需要保存內部狀態的類設計爲原發器。
- Memento(備忘錄):備忘錄用於存儲原發器的內部狀態,根據原發器來決定保存哪些內部狀態。備忘錄的設計一般可以參考原發器的設計,根據實際需要確定備忘錄中的屬性。需要注意的是,除了原發器本身與負責人類之外,備忘錄對象不能直接供其他類使用,原發器的設計在不同的編程語言中實現機制會有所不同。
- Caretaker(負責人):負責人又稱爲管理者,它負責保存備忘錄,但是不能對備忘錄的內容進行操作或檢查。在負責人類中可以存儲一個或多個備忘錄對象,它只負責儲存對象,而不能修改對象,也無須知道對象的實現細節。
代碼
Originator
public class Originator {
private String state;
public Originator(String state) {
this.state = state;
}
// 創建一個備忘錄對象
public Memento createMemento() {
return new Memento(this);
}
// 根據備忘錄對象恢復原發器狀態
public void restoreMemento(Memento memento) {
state = memento.getState();
}
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
Memento
// 備忘錄類,默認可見性,包內可見
class Memento {
private String state;
public Memento(Originator originator) {
state = originator.getState();
}
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
Caretaker
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
Test
public class Test {
public static void main(String[] args) {
// 創建原發器對象
Originator originator = new Originator("state1");
System.out.println(originator.getState());
// 創建負責人對象,保存創建的備忘錄對象
Caretaker caretaker = new Caretaker();
caretaker.setMemento(originator.createMemento());
originator.setState("state2");
System.out.println(originator.getState());
// 從負責人對象中取出備忘錄,實現撤銷
originator.restoreMemento(caretaker.getMemento());
System.out.println(originator.getState());
}
}
Console
state1
state2
state1
實現多次撤銷
MementoCaretaker
import java.util.ArrayList;
import java.util.List;
public class MementoCaretaker {
// 定義一個集合來儲存備忘錄
private List<Memento> mementoList = new ArrayList<>();
public Memento getMemento(int i) {
return mementoList.get(i);
}
public void setMemento(Memento memento) {
mementoList.add(memento);
}
}
Client
public class Client {
public static void main(String[] args) {
// 定義一個索引來記錄當前狀態所在位置
int index = -1;
// 創建原發器對象
Originator originator = new Originator("state1");
System.out.println(originator.getState());
MementoCaretaker mementoCaretaker = new MementoCaretaker();
// 設置備忘錄
mementoCaretaker.setMemento(originator.createMemento());
index++;
originator.setState("state2");
System.out.println(originator.getState());
Memento memento = mementoCaretaker.getMemento(index);
System.out.println(memento.getState());
// 撤銷
originator.restoreMemento(mementoCaretaker.getMemento(index));
index--;
System.out.println(index);
}
}
優/缺點與適用環境
- 優點
- 提供了一種狀態恢復的實現機制,使得用戶可以方便地回到一個特定的歷史步驟,當新的狀態無效或者存在問題時可以使用暫時存儲起來的備忘錄將狀態復原。
- 備忘錄實現了對信息的封裝,一個備忘錄對象時一種原發器對象狀態的表示,不會被其他代碼所改動。備忘錄保存了原發器的狀態,採用列表、堆棧等集合來儲存備忘錄對象可以實現多次撤銷操作。
- 缺點
- 資源消耗過大,如果需要保存的原發器類成員變量太多,就不可避免地需要佔用大量的存儲空間,每次保存一次對象的狀態都需要消耗一定的系統資源。
- 適用環境
- 保存一個對象在某一個時刻的全部或部分狀態,這樣以後需要時它能夠恢復到先前的狀態,實現撤銷操作。
- 防止外界對象破壞一個對象的歷史狀態的封裝性,避免將對象歷史狀態的實現細節暴露給外界對象。