前言

尊重原创,本系列文本解析部分主要基于Candidate for Master’s Degree School of Computer Wuhan University的K_Eckel([email protected])《设计模式精解-GoF 23 种设计模式解析附 C++实现源码》。为了避免重造轮子,本系列博文对源码在ubuntu16.04下做了验证并上传到了gitee,再次感谢。

如有问题,可邮件联系我([email protected])并共同探讨解决方案。

目录

创建型模式(Creating Pattern)

Factory 模式 | AbstactFactory 模式 | Singleton 模式 | Builder 模式 | Prototype 模式

结构型模式(Structrual Pattern)

Bridge 模式 | Adapter 模式 | Decorator 模式 | Composite 模式 | Flyweight 模式 | Facade 模式 | Proxy 模式

行为型模式(Behavioral Pattern)

Template 模式 | Strategy 模式 | State 模式 | Observer 模式 | Memento 模式 | Mediator 模式 | Command 模式 | Visitor 模式 | Iterator 模式 | Interpreter 模式 | Chain of Responsibility 模式

Memento 模式简介:

   备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。比如Windows里的ctri + z

问题:

   没有人想犯错误,但是没有人能够不犯错误。犯了错误一般只能改过,却很难改正(恢复)。世界上没有后悔药,但是我们在进行软件系统的设计时候是要给用户后悔的权利(实际上可能也是用户要求的权利:)),我们对一些关键性的操作肯定需要提供诸如撤销(Undo)的操作。那这个后悔药就是Memento模式提供的。

模式选择

   Memento模式的关键就是要在不破坏封装行的前提下,捕获并保存一个类的内部状态,这样就可以利用该保存的状态实施恢复操作。为了达到这个目标,可以在后面的实现中看到我们采取了一定语言支持的技术。Memento模式的典型结构图为:
Memento Pattern
图 1:Memento 模式结构示意图

实现

完整代码示例(code)

   Memento模式的实现很简单,这里为了方便初学者的学习和参考,将给出完整的实现代码(所有代码采用 C++实现,并在 Visual Studio Code,Version: 1.36.1 下测试运行)。

源码gitee地址:点击这里

代码目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\behavioralPattern\Memento> tree /F     
卷 Windows 的文件夹 PATH 列表
卷序列号为 F0C5-AFA6
C:.
├─include
│ Memento.h

└─src
a.out
main.cpp
Memento.cpp

PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\behavioralPattern\Memento>

Memento.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Memento.h

#ifndef _MEMENTO_H_
#define _MEMENTO_H_

#include <string>

using namespace std;

class Memento;

class Originator {
public:
typedef string State;
Originator();
Originator(const State& sdt);
~Originator();
Memento* CreateMemento();
void SetMemento(Memento* men);
void RestoreToMemento(Memento* mt);
State GetState();
void SetState(const State& sdt);
void PrintState();

private:
State _sdt;
Memento* _mt;
};

class Memento {
private:
//这是最关键的地方,将 Originator 为friend 类,可以访问内部
//信息,但是其他类不能访问
friend class Originator;
typedef string State;
Memento(/* args */);
Memento(const State& sdt);
~Memento();
void SetState(const State& sdt);
State GetState();
State _sdt;

public:
};

#endif //~_MEMENTO_H_

Memento.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Memento.cpp

#include "../include/Memento.h"
#include <iostream>

using namespace std;

typedef string State;

Originator::Originator(/* args */) {
_sdt = "";
_mt = 0;
}
Originator::Originator(const State& sdt) {
_sdt = sdt;
_mt = 0;
}
Originator::~Originator() {}
Memento* Originator::CreateMemento() { return new Memento(_sdt); }
State Originator::GetState() { return _sdt; }
void Originator::SetState(const State& sdt) { _sdt = sdt; }
void Originator::PrintState() { cout << this->_sdt << "....." << endl; }
void Originator::SetMemento(Memento* men) {}
void Originator::RestoreToMemento(Memento* mt) { this->_sdt = mt->GetState(); }

Memento::Memento(const State& sdt) { _sdt = sdt; }
State Memento::GetState() { return _sdt; }
void Memento::SetState(const State& sdt) { _sdt = sdt; }
Memento::~Memento() {}

main.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// main.cpp

#include <iostream>
#include "../include/Memento.h"

using namespace std;

int main(int argc, char* argv[]) {
Originator* o = new Originator();
o->SetState("old"); //备忘前状态
o->PrintState();
Memento* m = o->CreateMemento(); //将状态备忘
o->SetState("new"); //修改状态
o->PrintState();
o->RestoreToMemento(m); //恢复修改前状态
o->PrintState();

return 0;
}

代码说明

   Memento模式的关键就是friend class Originator;我们可以看到,Memento的接口都声明为private,而将Originator声明为Memento的友元类。我们将Originator的状态保存在Memento类中,而将Memento接口private起来,也就达到了封装的功效。在Originator类中我们提供了方法让用户后悔:RestoreToMemento(Memento* mt);我们可以通过这个接口让用户后悔。在测试程序中,我们演示了这一点:Originator的状态由old变为new最后又回到了old

编译运行结果:

1
2
3
4
5
6
PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\behavioralPattern\Memento\src> g++ *.cpp -std=c++11
PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\behavioralPattern\Memento\src> .\a.exe
old.....
new.....
old.....
PS C:\Users\guopz\Desktop\GiteeBlog\designpatternsbycpipei\behavioralPattern\Memento\src>

讨论

   在Command模式中,Memento模式经常被用来维护可以撤销(Undo)操作的状态。这一点将在Command模式具体说明。