Memento 备忘录模式也属于“状态变化”模式,它是一个小模式,在今天来看有些过时,当今已经很少使用当前模式实现需求,思想却不变(信息隐藏),目前多使用序列化方案来实现。本系列所介绍的模式,有一些随着时代的变化,有一些过时。
文章目录
- 1. 动机( Motivation)
- 2. 模式定义
- 3. Memento 备忘录模式代码实现
- 4. 结构( Structure )
- 5. 要点总结
- 6. 其他参考
1. 动机( Motivation)
- 在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。
Memento 备忘录模式主要解决维持封装性的前提下,怎么样去实现对象的状态
- 如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性
2. 模式定义
在不破坏(Originator)封装性的前提下,捕获一个对象的内部状态(Memento mem = orginator.createMomento()),并在该对象之外保存
这个状态。这样以后就可以将该对象恢复到原先保存的状态。
----《设计模式》GoF
3. Memento 备忘录模式代码实现
假设下面的对象是需要保存状态的对象,他的状态可能有很多,此处只释义性的放了字符串state
,省略号代表还有其他很多的状态。
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
这个对象有一个需求,我们想在某些点把它的状态拍一些内存快照存起来,我们设计了另外一个对象,他的状态内部表示是和Originator对应的为state
,当然在现实实现中,这个状态有可能只摘取Originator中某些有效的状态,在实现上也不一定一模一样,Originator中可能是一些字段,在Memento中可能是一个内存流、一个经过base 64编码之后的字符串。又提供了一定的接口供Originator访问
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
代码分析:
Originator中的利用以下代码将现有的状态塞进来,创建一个Momento,Memento m(state);
在不同平台的实现可能相当复杂,往往使用编码器访问转成其他的存储模式-内存流、字符串,最后再返回对象。以下的代码就相当于当前内存状态拍照
Memento createMomento() {
Memento m(state);
return m;
}
使用:orginator称为原发器,Memento mem = orginator.createMomento();
创建出一个备忘录并存储到备忘录的对象中(稳定,不动的),后在程序运行时更改原发器的状态//... 改变orginator状态
,在某一点需要把之前那个点存储的对象的状态恢复,orginator.setMomento(memento);
中orginator点setMomento,改变回原状态,state = m.getState();
是非常示意性的代码,具体在实现过程中可能会比较复杂。
int main()
{
Originator orginator;
//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();
//... 改变orginator状态
//从备忘录中恢复
orginator.setMomento(memento);
}
整体代码如下:
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
int main()
{
Originator orginator;
//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();
//... 改变orginator状态
//从备忘录中恢复
orginator.setMomento(memento);
}
Memento 备忘录理解起来比较简单,但是到不同平台上,具体实现会不同。
4. 结构( Structure )
5. 要点总结
-
备忘录(Memento)存储原发器(Originator)对象的内部状态,在需要时恢复原发器状态。
-
Memento模式的核心是信息隐藏,即Originator需要向外界隐藏信息,保持其封装性。但同时又需要将状态保持到外界(Memento)
-
由于现代语言运行时(如C#、Java等)都具有相当的
对象序列化支持
,因此往往采用效率较高、又较容易正确实现的序列化方案来实现Memento模式。
6. 其他参考
C++设计模式——备忘录模式