折騰Java設計模式之備忘錄模式

原文地址:折騰Java設計模式之備忘錄模式html

備忘錄模式

Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later.java

在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。git

所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣能夠在之後將對象恢復到原先保存的狀態。不少時候咱們老是須要記錄一個對象的內部狀態,這樣作的目的就是爲了容許用戶取消不肯定或者錯誤的操做,可以恢復到他原先的狀態,使得他有"後悔藥"可吃。經過一個備忘錄類專門存儲對象狀態。客戶不與備忘錄類耦合,與備忘錄管理類耦合。github

備忘錄模式UML

uml

UML類圖

Caretaker類是指用於保存(createMemento())和還原(restore(memento))發起方內部狀態的Originator類。 發起方類實現 (1)createMemento(),經過建立和返回存儲發起方當前內部狀態的memento對象 (2)經過從傳入的memento對象還原狀態來還原(memento)。設計模式

UML時序圖

(1)保存發起人的內部狀態:Caretaker對Originator調用createMemento(),建立memento對象,保存其當前內部狀態(setState()),並將memento返回給Caretaker。微信

(2)恢復發起人的內部狀態:Caretaker對Originator調用restore(memento),並指定存儲應恢復狀態的memento對象。發起者從memento獲取狀態(getState())以設置其本身的狀態。this

備忘錄模式角色結構

(1) 備忘錄(Memento)角色:備忘錄角色存儲「備忘發起角色」的內部狀態。「備忘發起角色」根據須要決定備忘錄角色存儲「備忘發起角色」的哪些內部狀態。爲了防止「備忘發起角色」之外的其餘對象訪問備忘錄。備忘錄實際上有兩個接口,「備忘錄管理者角色」只能看到備忘錄提供的窄接口——對於備忘錄角色中存放的屬性是不可見的。「備忘發起角色」則可以看到一個寬接口——可以獲得本身放入備忘錄角色中屬性。設計

(2) 備忘發起(Originator)角色:「備忘發起角色」建立一個備忘錄,用以記錄當前時刻它的內部狀態。在須要時使用備忘錄恢復內部狀態。rest

(3) 備忘錄管理者(Caretaker)角色:負責保存好備忘錄。不能對備忘錄的內容進行操做或檢查。code

乾貨示例

源碼地址

public class Caretaker {

​    public static void main(String[] args) {
​        List<Memento> savedStates = new ArrayList();
​        Originator originator = new Originator();
​        originator.set("State1");
​        originator.set("State2");
​        savedStates.add(originator.saveToMemento());

​        originator.set("State3");
​        savedStates.add(originator.saveToMemento());

​        originator.set("State4");
​        originator.restoreFromMemento(savedStates.get(1));
​    }
}


@Slf4j
public class Originator {

​    private String state;

​    //狀態更改
​    public void set(String state) {
​        this.state = state;
​        log.info("Originator: Setting state to {}", state);
​    }

​    //將狀態保存到備忘錄裏
​    public Memento saveToMemento() {
​        log.info("Originator: Saving to Memento.");
​        return new Memento(this.state);
​    }

​    //從備忘錄裏取出狀態並回滾
​    public void restoreFromMemento(Memento memento) {
​        this.state = memento.getState();
​        log.info("Originator: State after restoring from Memento: {}", state);
​    }
}


@Data
@AllArgsConstructor
public class Memento {

​    //狀態維護
​    private String state;

}

示例結果

image-2

從上述代碼中看的出,隨着狀態變動,用List維護髮起者的狀態列表,從備忘錄中取出狀態以便回退狀態。

java中的使用

生成對象狀態的一個快照,以便對象能夠恢復原始狀態而不用暴露自身的內容。Date對象經過自身內部的一個long值來實現備忘錄模式。

java.util.Date

java.io.Serializable

總結

優勢

一、給用戶提供了一種能夠恢復狀態的機制,可使用戶可以比較方便地回到某個歷史的狀態。 二、實現了信息的封裝,使得用戶不須要關心狀態的保存細節。

缺點

消耗資源。若是類的成員變量過多,勢必會佔用比較大的資源,並且每一次保存都會消耗必定的內存。

使用場景

一、須要保存/恢復數據的相關狀態場景。 二、提供一個可回滾的操做。

注意事項

一、爲了符合迪米特原則,還要增長一個管理備忘錄的類。 二、爲了節約內存,可以使用原型模式+備忘錄模式。

參考

備忘錄模式|菜鳥教程

Memento pattern

細數JDK裏的設計模式

歡迎關注

微信公衆號

相關文章
相關標籤/搜索