備忘錄模式

備忘錄模式是一种软件设计模式，可以將一個物件內部私有的狀態公開。可以使用此模式的一個例子是將物件回復到其先前的状态（撤消變更），還有的例子是版本控制，以及自定义序列化。 備忘錄模式主要由三個角色來實現：發起者、管理員和備忘錄。發起者是具有內部狀態的角色。管理員可以對發起起者做一些操作，尤其是希望能够撤消變更的操作。竹管理員首先向發起者索要一件備忘錄。然后它执行此操作（或操作序列）。為了可以回滚到操作之前的状态，它将備忘錄返回给发起者。備忘錄本身是一个不透明的物件（管理員不能或不應更改此物件）。使用此模式時，應注意發起者是否可能更改其他物件或資源——備忘錄模式是對單一物件進行操作。 備忘錄模式的經典範例有伪随机数生成器（PRNG）（每個消費者（管理員）在初始化偽隨機數生成器（發起者）時，若使用相同的種子值（備忘錄），可以產生相同的亂數序列），此外，還有有限状态机及其狀態。 備忘錄設計模式是著名的《設計模式：可復用物件導向軟體的基礎》所收錄的二十三個之一。此書描述了如何解決常見的設計問题，以設計出彈性且異重用的物件導向软件（亦即更容易實現、更改、测试、维护和重用的物件）。備忘錄模式是由 Noah Thompson、David Espiritu 和 Drew Clinkenbeard 博士为惠普早期产品创建的。 物件的内部狀態須要保存在外部，以便之後可將物件回復到此狀態。 不違反物件的封裝性。 問题在於，一個良好設計的物件會被封装起来，其表示（資料結構）是隐藏在物件内部，且無法從外部存取。 让一个物件（發起者）本身负责 将其内部状态保存到（備忘錄）物件，並且 从（備忘錄）物件回復到以前的狀態。 只有產生此備忘錄的發起者可以存取它。 客户端（管理員）可以向發起者請求備忘錄（以保存發起者的内部状态）并将備忘錄传递回發起者（以恢复到先前的状态）。 这使得外部能够在不破壞其封装的情况下，保存和回復發起者的内部狀態。 請參考下面的 UML 類別圖和序列圖。 在上面的UML类图中， Caretaker 類別指向向 Originator 類別，用于保存（ createMemento() ）和恢复（ restore(memento) ）始发者的内部状态。Originator 類別實現了(1) createMemento() ，藉由創建並返回 Memento 物件，其記錄了發起者當前内部状态，(2) restore(memento)，藉由將 Memento 物件傳入，以回復狀態。 UML序列图显示了运行时交動：(1) 保存发起者的内部状态： Caretaker对象在Originator对象上调用createMemento() ，创建一个Memento对象，保存其当前的内部状态 ( setState() )，并将Memento返回给Caretaker 。(2) 恢复Originator的内部状态： Caretaker对Originator对象调用restore(memento) ，并指定存储应恢复状态的Memento对象。 Originator从Memento获取状态 ( getState() ) 以设置自己的状态。 以下的 Java 程序说明了備忘錄模式的“撤消變更”用法。 import java.util.List; import java.util.ArrayList; class Originator { private String state; // 這個類別可以包含其它不用存在 State 中的備忘錄 public void set(String state) { this.state = state; System.out.println("Originator: Setting state to " + state); } public Memento saveToMemento() { System.out.println("Originator: Saving to Memento."); return new Memento(this.state); } public void restoreFromMemento(Memento memento) { this.state = memento.getSavedState(); System.out.println("Originator: State after restoring from Memento: " + state); } public static class Memento { private final String state; public Memento(String stateToSave) { state = stateToSave; } // accessible by outer class only private String getSavedState() { return state; } } } class Caretaker { public static void main(String[] args) { List<Originator.Memento> savedStates = new ArrayList<Originator.Memento>(); 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)); } } 输出是： Originator: Setting state to State1 Originator: Setting state to State2 Originator: Saving to Memento. Originator: Setting state to State3 Originator: Saving to Memento. Originator: Setting state to State4 Originator: State after restoring from Memento: State3 本示例使用 String 作为状态，它是 Java 中的不可变物件。在现实生活中，状态几乎总是一个可变物件，在这种情况下，必须创建状态的副本。 必须指出的是，所展示的实现有一个缺点：它声明了一个内部类。如果備忘錄可以适用于多个发起者，則會更好。 实现Memento 还有其他三种主要方式： 序列化。 在同一个包中声明的類別。 还可以通过代理来访问该物件，代理可以实现对物件的任何保存/恢复操作。 備忘錄模式允许人們在不違反封装的情况下捕获物件的内部状态，以便以后可以根據需求來撤消變更/回復變更。從这里可以看出，備忘錄物件实际上用于恢复物件中所做的更改。 class Memento { private readonly string savedState; private Memento(string stateToSave) { savedState = stateToSave; } public class Originator { private string state; // The class could also contain additional data that is not part of the // state saved in the memento. public void Set(string state) { Console.WriteLine("Originator: Setting state to " + state); this.state = state; } public Memento SaveToMemento() { Console.WriteLine("Originator: Saving to Memento."); return new Memento(state); } public void RestoreFromMemento(Memento memento) { state = memento.savedState; Console.WriteLine("Originator: State after restoring from Memento: " + state); } } } class Caretaker { static void Main(string[] args) { var savedStates = new List<Memento>(); var originator = new Memento.Originator(); originator.Set("State1"); originator.Set("State2"); savedStates.Add(originator.SaveToMemento()); originator.Set("State3"); // We can request multiple mementos, and choose which one to roll back to. savedStates.Add(originator.SaveToMemento()); originator.Set("State4"); originator.RestoreFromMemento(savedStates[1]); } } """ 備忘錄模式範例 """ class Originator: _state = "" def set(self, state: str) -> None: print(f"Originator: Setting state to {state}") self._state = state def save_to_memento(self) -> "Memento": return self.Memento(self._state) def restore_from_memento(self, m: "Memento") -> None: self._state = m.get_saved_state() print(f"Originator: State after restoring from Memento: {self._state}") class Memento: def __init__(self, state): self._state = state def get_saved_state(self): return self._state saved_states = [] originator = Originator() originator.set("State1") originator.set("State2") saved_states.append(originator.save_to_memento()) originator.set("State3") saved_states.append(originator.save_to_memento()) originator.set("State4") originator.restore_from_memento(saved_states[1]) // The Memento pattern is used to save and restore the state of an object. // A memento is a snapshot of an object's state. var Memento = {// Namespace: Memento savedState : null, // The saved state of the object. save : function(state) { // Save the state of an object. this.savedState = state; }, restore : function() { // Restore the state of an object. return this.savedState; } }; // The Originator is the object that creates the memento. // defines a method for saving the state inside a memento. var Originator = {// Namespace: Originator state : null, // The state to be stored // Creates a new originator with an initial state of null createMemento : function() { return { state : this.state // The state is copied to the memento. }; }, setMemento : function(memento) { // Sets the state of the originator from a memento this.state = memento.state; } }; // The Caretaker stores mementos of the objects and // provides operations to retrieve them. var Caretaker = {// Namespace: Caretaker mementos : [], // The mementos of the objects. addMemento : function(memento) { // Add a memento to the collection. this.mementos.push(memento); }, getMemento : function(index) { // Get a memento from the collection. return this.mementos[index]; } }; var action_step = "Foo"; // The action to be executed/the object state to be stored. var action_step_2 = "Bar"; // The action to be executed/the object state to be stored. // 設置初始值 Originator.state = action_step; Caretaker.addMemento(Originator.createMemento());// save the state to the history console.log("Initial State: " + Originator.state); // Foo // 改變初始值 Originator.state = action_step_2; Caretaker.addMemento(Originator.createMemento()); // save the state to the history console.log("State After Change: " + Originator.state); // Bar // 回復到第一個狀態——撤消變更 Originator.setMemento(Caretaker.getMemento(0)); console.log("State After Undo: " + Originator.state); // Foo // 回復到第二個狀態——重做變更 Originator.setMemento(Caretaker.getMemento(1)); console.log("State After Redo: " + Originator.state); // Bar The Memento design pattern - Structure and Collaboration. w3sDesign.com. [2017-08-12].