**備忘錄模式**是一种软件设计模式，可以將一個物件內部私有的狀態公開。可以使用此模式的一個例子是將物件回復到其先前的状态（撤消變更），還有的例子是版本控制，以及自定义序列化。

備忘錄模式主要由三個角色來實現：發起者、管理員和備忘錄。發起者是具有內部狀態的角色。管理員可以對發起起者做一些操作，尤其是希望能够撤消變更的操作。竹管理員首先向發起者索要一件備忘錄。然后它执行此操作（或操作序列）。為了可以回滚到操作之前的状态，它将備忘錄返回给发起者。備忘錄本身是一个不透明的物件（管理員不能或不應更改此物件）。使用此模式時，應注意發起者是否可能更改其他物件或資源——備忘錄模式是對單一物件進行操作。

備忘錄模式的經典範例有伪随机数生成器（PRNG）（每個消費者（管理員）在初始化偽隨機數生成器（發起者）時，若使用相同的種子值（備忘錄），可以產生相同的亂數序列），此外，還有有限状态机及其狀態。

概述
--

備忘錄設計模式是著名的《*設計模式：可復用物件導向軟體的基礎*》所收錄的二十三個之一。此書描述了如何解決常見的設計問题，以設計出彈性且異重用的物件導向软件（亦即更容易實現、更改、测试、维护和重用的物件）。備忘錄模式是由 Noah Thompson、David Espiritu 和 Drew Clinkenbeard 博士为惠普早期产品创建的。

### 備忘錄設計模式可以解決什麼問題？

* 物件的内部狀態須要保存在外部，以便之後可將物件回復到此狀態。
* 不違反物件的封裝性。

問题在於，一個良好設計的物件會被封装起来，其表示（資料結構）是隐藏在物件内部，且無法從外部存取。

### 備忘錄設計模式描述了什么解决方案？

让一个物件（發起者）本身负责

* 将其内部状态保存到（備忘錄）物件，並且
* 从（備忘錄）物件回復到以前的狀態。

只有產生此備忘錄的發起者可以存取它。

客户端（管理員）可以向發起者請求備忘錄（以保存發起者的内部状态）并将備忘錄传递回發起者（以恢复到先前的状态）。

这使得外部能够在不破壞其封装的情况下，保存和回復發起者的内部狀態。

請參考下面的 UML 類別圖和序列圖。

结构
--

### UML 類別圖和序列圖

備忘錄設計模式的 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 範例
-------

以下的 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 还有其他三种主要方式：

1. 序列化。
2. 在同一个包中声明的類別。
3. 还可以通过代理来访问该物件，代理可以实现对物件的任何保存/恢复操作。

C# 示例
-----

備忘錄模式允许人們在不違反封装的情况下捕获物件的内部状态，以便以后可以根據需求來撤消變更/回復變更。從这里可以看出，*備忘錄物件*实际上用于*恢复*物件中所做的更改。

```
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]);
 }
}

```

Python 範例
---------

```
"""
備忘錄模式範例
"""

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])

```

JavaScript 範列
-------------

```
// 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

```