學習筆記【23種設計模式-第十九節:Memento Pattern 備忘錄模式】
阿新 • • 發佈:2020-12-19
Memento Pattern 備忘錄模式
簡述
- 備忘錄模式在不破壞封裝的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。
- 可以這裡理解備忘錄模式:現實生活中的備忘錄是用來記錄某些要去做的事情,或者是記錄已經達成的共同的意見的事情,以防忘記。在軟體層面,備忘錄模式有著相同的意義,備忘錄物件主要用來記錄一個物件的某種狀態,或者某些資料,當要做回退時,可以從備忘錄物件裡獲取原來的資料進行恢復操作。
- 備忘錄模式屬於行為型模式。
角色
- Originator 物件,需要儲存狀態的。
- Memento 備忘錄物件,負責儲存好記錄,即Originator的內部狀態。
- Caretaker:守護者物件,負責儲存多個備忘錄物件,使用集合管理,提高效率
- 說明:如果希望儲存多個originator物件的不同時間的狀態,也可以只需要一個HashMap< String,集合>
程式碼:
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento saveStateMemento(){
return new Memento(state);
}
public void getStateFromMemento(Memento memento){
state=memento.getState();
}
}
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState () {
return state;
}
}
public class Caretaker {
private List<Memento> mementoList=new ArrayList<>();
public void add(Memento memento){
mementoList.add(memento);
}
public Memento get(int index){
return mementoList.get(index);
}
}
public class Client {
public static void main(String[] args) {
Originator originator=new Originator();
Caretaker caretaker=new Caretaker();
originator.setState("狀態#1:生命值100");
caretaker.add(originator.saveStateMemento());
originator.setState("狀態#2:生命值80");
caretaker.add(originator.saveStateMemento());
originator.setState("狀態#1:生命值50");
caretaker.add(originator.saveStateMemento());
System.out.println("當前狀態為:"+originator.getState());
originator.getStateFromMemento(caretaker.get(0));//得到狀態#1
System.out.println("恢復,當前的狀態為:"+originator.getState());
}
}
例子
遊戲角色恢復:Memento,兩個屬性,攻擊力vit與防禦力def。Caretaker類,有Memento屬性(儲存一次就不用集合了)。GameRole,有createMemento方法(返回Memento);有recover方法,恢復到備忘錄;有display方法列印狀態。
Memento類:
public class Memento {
private int vit;
private int def;
public Memento(int vit, int def) {
this.vit = vit;
this.def = def;
}
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
}
Caretaker類:
public class Caretaker {
private Memento memento;
//對GameRole保持多次狀態
// private ArrayList<Memento> mementos;
//對多個GameRole儲存多次狀態
// private HashMap<String,ArrayList<Memento>> rolesMementos;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
GameRole類:
public class GameRole {
private int vit;
private int def;
public GameRole(int vit, int def) {
this.vit = vit;
this.def = def;
}
public void setVit(int vit) {
this.vit = vit;
}
public void setDef(int def) {
this.def = def;
}
public Memento createMemento(){
return new Memento(vit,def);
}
public void recoverFromMemento(Memento memento){
vit=memento.getVit();
def=memento.getDef();
}
public void display(){
System.out.println("角色當前狀態:攻擊力【"+vit+"】,防禦力【"+def+"】。");
}
}
Client主方法
public class Client {
public static void main(String[] args) {
GameRole gameRole=new GameRole(100,100);
System.out.println("大戰前狀態:");
gameRole.display();
Caretaker caretaker=new Caretaker();
caretaker.setMemento(gameRole.createMemento());
System.out.println("大戰進行了十分鐘:");
gameRole.setVit(70);
gameRole.setDef(60);
gameRole.display();
System.out.println("大戰後恢復:");
gameRole.recoverFromMemento(caretaker.getMemento());
gameRole.display();
}
}
結果:
注意事項
- 給使用者提供一種可以恢復狀態的機制,可以使使用者能夠比較方便的回到某個歷史的狀態。
- 實現了資訊的封裝,使得使用者不需要關心狀態的儲存細節。
- 如果類的成員變數過多,勢必會佔用比較大的資源,而且每一次儲存都會消耗一定的記憶體,這個需要注意。
- 適用的場景:1、後悔藥。2、打遊戲時的存檔。3、windows裡的ctrl+z。4、IE的後退。5、資料庫的事務管理。
- 為了節約記憶體,備忘錄模式可以和原型模式配合使用。