一、定义
行为型模式之一。
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
(在不破坏封装性的前提下,捕获一个对象的内部状态并存储到外部,使得之后这个对象可以被恢复到此备份的状态。)
二、结构解析
备忘录模式的一般结构有三种角色: 发起人、备忘录、备忘录管理员。
发起者(Originator):有备忘需求的对象。可以创建备忘录,或通过备忘录恢复到备份的某一状态。
备忘录(Memento):持有并只持有发起者某时刻的一个状态(相当于发起者的一次快照)。一般而言,备忘录被创建后,持有的状态应该是只读的,所以备忘录应该在构造时初始化,并且不提供改变状态的方法。备忘录只应被发起者使用。
备忘录管理者(CareTaker):可以当作是一个备忘录仓库,聚合/持有多个备忘录,可能采用字典、堆栈、列表等不同的集合存储备忘录,以应对不同的备忘需求。。发起者创建的备忘录将被放在此处,发起者恢复状态时也从这里获取备忘录。
三、评价
备忘录模式又叫快照模式,用于备份系统某时刻的状态,常见于游戏存档、版本控制、浏览记录等。
又可分为 “白箱备忘录” 和 “黑箱备忘录” 。区别是,黑箱备忘录持有的状态只对发起者公开,更安全(定义中的 “不破坏封装性”)。
Java中,用 “备忘录作为发起者的内部类,并将备忘录的方法全部设为私有” 来实现黑箱备忘录。这种方式在C#中不可用!原因是,C#和Java的内部类性质有所区别:Java中,外部类内部可以直接访问内部类的私有成员,而在C#中不行。
因此,我换了一种方式来实现了“黑箱”:备忘录中提供公有一个方法,反调“以参数形式传入的发起者”的改变状态接口。这样,虽然此方法是公开的,但只可能被发起者使用。
或者也可以直接在备忘录构造时就引用创建它的发起者,之后只提供一个恢复接口,此时,备忘录就只能被创建它的发起者使用了。
注意:在备份状态时,要小心处理引用类型(要对其进行深拷贝)。
四、实现
using System.Collections.Generic;
using UnityEngine;
namespace Memento
{
//状态数据类用于辅助说明
public struct State
{
public string name; //状态名
//...状态的其他数据
public State(string name/*, ...状态的其他数据*/)
{
this.name = name;
}
}
//-------------------------------------
//备忘录
public class Memento
{
private State state;
//一般而言,备忘录被创建后,持有的State应该是只读的,所以在构造时初始化,并且不提供SetState()方法
public Memento(State state)
{
this.state = state;
}
//白箱备忘录
//暴露了备忘录中的状态给任何对象
//public State GetState()
//{
// return state;
//}
//黑箱备忘录
//提供一个方法,反调“以参数形式传入的Originator”的改变状态接口(或者将originator直接放在Memento构造时)。
//这样, 虽然这个方法是公有的,但只可能被Originator使用, 保证了备忘录的安全性。缺点是, Memento反向依赖了Originator,增加了耦合度。
public void Restore(Originator originator)
{
originator.ChangeState(this.state);
}
//另一种黑箱备忘录
//Memento构造时就传入 originator对象
//public void Restrore()
//{
// originator.ChangeState(this.state);
//}
}
public class Originator
{
private State state;
//自身状态自然变化
public void ChangeState(State state)
{
this.state = state;
}
//获取当前自身状态
public State GetState()
{
return state;
}
//创建备忘录,保存当前状态
public Memento CreateMemento()
{
return new Memento(state);
}
//使用备忘录恢复状态。
//public void RestoreFromMemento(Memento Memento)
//{
// this.state = Memento.GetState();
//}
public void RestoreFromMemento(Memento Memento)
{
Memento.Restore(this);
}
}
public class CareTaker
{
private Dictionary<string, Memento> mementoDict = new Dictionary<string, Memento>();
public void AddMemento(string stateName, Memento state)
{
mementoDict.Add(stateName, state);
}
public Memento GetMemento(string stateName )
{
return mementoDict[stateName];
}
}
public class Client
{
public static void Main()
{
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.ChangeState(new State("状态一"));
originator.ChangeState(new State("状态二"));
//存储当前状态
string key = originator.GetState().name;
careTaker.AddMemento(key, originator.CreateMemento());
originator.ChangeState(new State("状态三"));
//恢复到之前备份的某一状态
originator.RestoreFromMemento(careTaker.GetMemento(key));
Debug.Log("目前状态:" + originator.GetState().name);
}
}
}