前言
尊重原创,本系列文本解析部分主要基于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模式的典型结构图为:
图 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模式具体说明。