1. 程式人生 > 其它 >學習筆記【23種設計模式-第十九節:Memento Pattern 備忘錄模式】

學習筆記【23種設計模式-第十九節:Memento Pattern 備忘錄模式】

技術標籤:# 23種設計模式java設計模式

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、資料庫的事務管理。
  • 為了節約記憶體,備忘錄模式可以和原型模式配合使用。