Java設計模式之備忘錄模式

備忘錄模式(Memento pattern): 當你需要讓對象返回之前的狀態時(例如, 你的用戶請求”撤銷”), 你使用備忘錄模式。

備忘錄模式的詳解

類圖:

這裏寫圖片描述

角色說明:
發起人角色(Originator):此角色主要負責創建一個含有當前內部狀態的備忘錄對象,並使用被網羅對象存儲其內部狀態。

負責人角色(Caretaker):負責人角色主要負責保存備忘錄對象,但不檢查備忘錄對象的內容。

備忘錄角色(Memento):備忘錄主要負責將發起人對象(Originator)的內部狀態存儲起來。備忘錄可以根據發起人對象的判斷來決定存儲多少發起人對象的內部狀態。備忘錄還可以保護其內容不被發起人對象之外的任何對象所讀取。

備忘錄有兩個等效的接口:

寬接口:發起人對象可以看到一個寬接口,這個寬接口允許它讀取所有的數據,以便根據這些數據恢復這個發起人對象的內部狀態。

窄接口:負責人對象(和其他除發起人對象之外的任何對象)看到的是備忘錄的窄接口,這個窄接口只允許它把備忘錄對象傳給其他的對象。

透明備忘錄模式

備忘錄角色對任何對象都提供一個接口,即上面說的寬接口。備忘錄角色的內容所存儲的狀態就對所有對象公開,所以又叫透明實現。

代碼演示,發起人角色類:

/**
 * 發起人角色類
 * @author Layne
 *
 */
public class Originator {

    private String state;

    /**
     * 工廠方法,返回一個新的備忘錄對象,並將發起人的狀態傳入
     */
    public Memento createMemento() {
        return new Memento(state);
    }

    /**
     * 將發起人恢復到備忘錄對象所記載的狀態
     */
    public void restoreMemento(Memento memento) {
        this.state = memento.getState();
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

}

負責人角色類:

/**
 * 負責人角色類
 * @author Layne
 *
 */
public class Caretaker {
    //持有一個備忘錄對象
    private Memento memento;

    /**
     * 備忘錄的取值方法
     */
    public Memento retrieveMemento() {
        return this.memento;
    }

    /**
     * 備忘錄的賦值方法
     */
    public void saveMemento(Memento memento) {
        this.memento = memento;
    }
}

備忘錄角色類:

/**
 * 備忘錄角色類
 * @author Layne
 *
 */
public class Memento {

    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

}

客戶端測試類:

public class Client {

    public static void main(String[] args) {

        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        // 設置負責人對象的狀態
        originator.setState("smile");
        System.out.println("初始狀態:"+originator.getState());


        // 創建備忘錄對象,並將發起人對象的狀態儲存起來
        caretaker.saveMemento(originator.createMemento());
        // 修改發起人的狀態
        originator.setState("cry");
        System.out.println("修改後狀態:"+originator.getState());

        // 恢復發起人對象的狀態
        originator.restoreMemento(caretaker.retrieveMemento());
        System.out.println("恢復後狀態:"+originator.getState());
    }

}

運行結果:
這裏寫圖片描述


隱藏備忘錄模式

備忘錄角色對發起人角色提供了一個寬接口,而對其他對象提供一個窄接口,所以又叫隱藏實現。

將備忘錄類(Memento)設計成發起人類(Originator)的內部類。從而將備忘錄類對象封裝在發起人類裏面;在外部提供一個標識接口MementoImpl給負責人類(Caretaker)以及其他對象。
這樣發起人類看到的是備忘錄類的所有接口,而負責人類記憶其他對象看到的僅僅是標識接口MementoImpl所暴露出來的接口。

類圖:

這裏寫圖片描述

代碼演示,標識接口:

//標識接口
public interface MementoImpl {

}

負責人角色類:

public class Caretaker {

    private MementoImpl memento;

    /**
     * 備忘錄取值方法
     */
    public MementoImpl retrieveMemento() {
        return memento;
    }

    /**
     * 備忘錄賦值方法
     */
    public void saveMemento(MementoImpl memento) {
        this.memento = memento;
    }
}

發起人角色類:

public class Originator {

    private String state;

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    /**
     * 工廠方法,返還一個新的備忘錄對象
     */
    public MementoImpl createMemento() {
        return new Memento(state);
    }

    /**
     * 發起人恢復到備忘錄對象記錄的狀態
     */
    public void restoreMemento(MementoImpl memento) {
        this.setState(((Memento) memento).getState());
    }

    private class Memento implements MementoImpl {

        private String state;

        /**
         * 構造方法
         */
        private Memento(String state) {
            this.state = state;
        }

        private String getState() {
            return state;
        }
    }
}

客戶端測試類:

public class Client {

    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        // 改變負責人對象的狀態
        originator.setState("smile");
        System.out.println("初始狀態:"+originator.getState());


        // 創建備忘錄對象,並將發起人對象的狀態存儲起來
        caretaker.saveMemento(originator.createMemento());
        // 修改發起人對象的狀態
        originator.setState("cry");
        System.out.println("修改後狀態:"+originator.getState());

        // 恢復發起人對象的狀態
        originator.restoreMemento(caretaker.retrieveMemento());
        System.out.println("恢復後狀態:"+originator.getState());
    }

}

運行結果:
這裏寫圖片描述

備忘錄模式優點:

  • 當發起人角色中的狀態改變時,有可能這是個錯誤的改變,我們使用備忘錄模式就可以把這個錯誤的改變還原。
  • 備份的狀態是保存在發起人角色之外的,這樣發起人角色就不需要對各個備份的狀態進行管理。

缺點:

  • 在實際應用中,備忘錄模式都是多狀態和多備份的,發起人角色的狀態需要存儲到備忘錄對象中,對資源的消耗是比較嚴重的。
發佈了129 篇原創文章 · 獲贊 146 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章