Java設計模式18:備忘錄模式(Mementor)

備忘錄模式

意圖

在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,以後可將該對象恢復到原先保存的狀態。顧名思義,就是提供備忘功能。

適用性

1、必須保存一個對象在摸一時刻的狀態,便於後續對他的恢復

2、如果一個用接口來讓其他對象直接得到這些狀態,將會暴露對象的實現細節並破壞對象的封裝性

結構

這裏寫圖片描述

Memento

備忘錄存儲原發器對象的內部狀態。原發器根據需要決定備忘錄存儲原發器的哪些狀態

防止原發器以外的其他對象訪問備忘錄。理想情況之允許生成本備忘錄的那個原發器訪問本備忘錄的內部狀態

Originator

原發器創建一個備忘錄,用以記錄當前時刻的內部裝阿嚏

使用備忘錄恢復內部狀態

Caretaker

負責保存備忘錄

不能對備忘錄的內容進行操作或者檢查

實現

實現就是一個簡單的模擬遊戲內存檔的一個操作,恢復操作則是選擇對應的存檔進行恢復

package memento;

/**
 * @Author fitz.bai
 * @Date 2018/9/6 15:46
 */
public class Zhuxian {
    private String state;
    private double latitude;
    private double longitude;

    public Zhuxian(String state, double latitude, double longitude) {
        this.state = state;
        this.latitude = latitude;
        this.longitude = longitude;
    }

    public String getState() {
        return state;
    }

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

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

    public ZhuxianMemento save() {
        return new ZhuxianMemento(this.state, this.latitude, this.longitude);
    }

    public void restore(ZhuxianMemento zhuxianMemento) {
        this.state = zhuxianMemento.getState();
        this.latitude = zhuxianMemento.getLatitude();
        this.longitude = zhuxianMemento.getLongitude();
    }

}
package memento;

/**
 * @Author fitz.bai
 * @Date 2018/9/6 15:49
 */
public class ZhuxianMemento {
    private String state;
    private double latitude;
    private double longitude;

    public ZhuxianMemento(String state, double latitude, double longitude) {
        this.state = state;
        this.latitude = latitude;
        this.longitude = longitude;
    }

    public String getState() {
        return state;
    }

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

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(int latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(int longitude) {
        this.longitude = longitude;
    }
}
package memento;

import java.util.ArrayList;

/**
 * @Author fitz.bai
 * @Date 2018/9/6 15:50
 */
public class MementoCaretaker {
    private ArrayList mementoList = new ArrayList();

    public ZhuxianMemento getMemento(int i) {
        return (ZhuxianMemento) mementoList.get(i);
    }

    public void setMemento(ZhuxianMemento memento) {
        mementoList.add(memento);
    }
}
package memento;

/**
 * @Author fitz.bai
 * @Date 2018/9/6 15:46
 */
public class Client {
    private static int index = -1;

    private static MementoCaretaker mementoCaretaker = new MementoCaretaker();

    public static void main(String[] args) {

        // 初始位置
        Zhuxian zhuxian = new Zhuxian("張小凡", 23.6, 54.6);

        // 存個檔
        mementoCaretaker.setMemento(zhuxian.save());
        display(zhuxian);

        // 傳送到別處
        zhuxian.setLatitude(65.2);

        // 存個檔
        mementoCaretaker.setMemento(zhuxian.save());
        display(zhuxian);

        // 再去往別處
        zhuxian.setLatitude(125.2);
        display(zhuxian);

        // 打不過了,快回到出生地
        zhuxian.restore(mementoCaretaker.getMemento(0));
        display(zhuxian);
    }

    private static void display(Zhuxian zhuxian) {
        System.out.println(zhuxian.getState() + "當前位置爲:" + "經度" + zhuxian.getLatitude() + "," + "緯度" + zhuxian.getLongitude());
    }
}
/**張小凡當前位置爲:經度23.6,緯度54.6
張小凡當前位置爲:經度65.2,緯度54.6
張小凡當前位置爲:經度125.2,緯度54.6
=================回檔==================
張小凡當前位置爲:經度23.6,緯度54.6
*/

其實備忘錄模式十分簡單,可以簡單理解爲,你有一個對象A,你想保存一下他,就將你需要的屬性值存儲到另外一個對象B中,而在用一個管理對象B的對象C將對象B存儲起來,等到需要的時候,再去對象C中找到對應的對象B,他就是你當時備忘起來的屬性。

注意封裝性

https://quanke.gitbooks.io/design-pattern-java

備忘錄是一個很特殊的對象,只有原發器對它擁有控制的權力,負責人只負責管理,而其他類無法訪問到備忘錄,因此我們需要對備忘錄進行封裝。

爲了實現對備忘錄對象的封裝,需要對備忘錄的調用進行控制,對於原發器而言,它可以調用備忘錄的所有信息,允許原發器訪問返回到先前狀態所需的所有數據;對於負責人而言,只負責備忘錄的保存並將備忘錄傳遞給其他對象;對於其他對象而言,只需要從負責人處取出備忘錄對象並將原發器對象的狀態恢復,而無須關心備忘錄的保存細節。理想的情況是隻允許生成該備忘錄的那個原發器訪問備忘錄的內部狀態。

在實際開發中,原發器與備忘錄之間的關係是非常特殊的,它們要分享信息而不讓其他類知道,實現的方法因編程語言的不同而有所差異,在C++中可以使用friend關鍵字,讓原發器類和備忘錄類成爲友元類,互相之間可以訪問對象的一些私有的屬性;在Java語言中可以將原發器類和備忘錄類放在一個包中,讓它們之間滿足默認的包內可見性,也可以將備忘錄類作爲原發器類的內部類,使得只有原發器纔可以訪問備忘錄中的數據,其他對象都無法使用備忘錄中的數據。

優點

1、它提供了一種狀態恢復的實現機制,使得用戶可以方便地回到一個特定的歷史步驟,當新的狀態無效或者存在問題時,可以使用暫時存儲起來的備忘錄將狀態復原。

2、備忘錄實現了對信息的封裝,一個備忘錄對象是一種原發器對象狀態的表示,不會被其他代碼所改動。備忘錄保存了原發器的狀態,採用列表、堆棧等集合來存儲備忘錄對象可以實現多次撤銷操作。

缺點

1、資源消耗過大,如果需要保存的原發器類的成員變量太多,就不可避免需要佔用大量的存儲空間,每保存一次對象的狀態都需要消耗一定的系統資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章