备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。(浏览器回退、编辑器撤销与重做、虚拟机生成快照与恢复、游戏悔棋等)
为什么使用备忘录模式备忘录模式允许你复制对象中的全部状态 (包括私有成员变量), 并将其独立于对象进行保存。 尽管大部分人因为 “撤销” 这个用例才记得该模式, 但其实它在处理事务 (比如需要在出现错误时回滚一个操作) 的过程中也必不可少;备忘录让对象自行负责创建其状态的快照。 任何其他对象都不能读取快照, 这有效地保障了数据的安全性
备忘录模式实现步骤1.提供一个原发器类:真正要被保存或恢复的对象,其负责创建一个备忘录,可以存储、恢复需要状态信息
2.提供一个备忘录类:用于存储原生器对象的的内部状态,防止外部直接访问原生器对象
3.提供一个管理者类:负责存储备忘录,但不能对备忘录内容进行操作和访问,只能将备忘录传递给其他对象
//下棋退步问题 #include备忘录模式优缺点#include #include using namespace std; class Memento { public: Memento(string name, pair pos) : name(name), pos(pos) {} string GetName() { return name; } pair GetPos() { return pos; } void Show() { cout << name << ":(" << pos.first << "," << pos.second << ")" << endl; } private: string name; pair pos; }; class Chess { public: Chess(string name, pair pos) : name(name), pos(pos) {} void SetChess(string name, pair pos) { this->name = name; this->pos = pos; } Memento* SaveState() { return new Memento(name, pos); } void Restore(Memento* memento) { name = memento->GetName(); pos = memento->GetPos(); } protected: string name; pair pos; }; class Caretaker { public: //存档 void AddMento(Memento* memento) { mementos.push_back(memento); step++; } //获取存档 Memento* GetMemento(int index) { step = index; return mementos[step]; } void Show() { for (int i = 0; i < step; i++) { cout << "step:" << i + 1 << "手" << endl; mementos[i]->Show(); } } protected: vector mementos; static int step; }; int Caretaker::step = 0; int main() { Chess* pc = new Chess("车", {4, 3}); Caretaker* pcaretaker = new Caretaker; pcaretaker->AddMento(pc->SaveState()); pcaretaker->Show(); cout << endl; pc->SetChess("马", {8, 8}); pcaretaker->AddMento(pc->SaveState()); pcaretaker->Show(); cout << endl; pc->SetChess("炮", {6, 6}); pcaretaker->AddMento(pc->SaveState()); pcaretaker->Show(); cout << endl; pc->Restore(pcaretaker->GetMemento(2)); pcaretaker->Show(); return 0; }
优点
-
你可以在不破坏对象封装情况的前提下创建对象状态快照
-
你可以通过让负责人维护原发器状态历史记录来简化原发器代码
缺点
-
如果客户端过于频繁地创建备忘录, 程序将消耗大量内存
-
负责人必须完整跟踪原发器的生命周期, 这样才能销毁弃用的备忘录
状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样
为什么使用状态模式模式建议你将所有特定于状态的代码抽取到一组独立的类中。 这样一来, 你可以在独立于其他状态的情况下添加新状态或修改已有状态, 从而减少维护成本;状态模式让你能够生成状态类层次结构, 通过将公用代码抽取到抽象基类中来减少重复
状态模式实现步骤1.提供一个上下文环境类:抽象一个客户程序需要的接口,将与状态相关的操作委托给当前的具体状态类对象来处理
2.提供一个抽象给状态类:定义一个接口以封装使用上下文环境的的一个特定状态相关的行为
3.提供一个具体状态类:实现抽象状态定义的接口
// #include状态模式优缺点using namespace std; class Context; class AbstractState { public: virtual void Handle(Context* p) = 0; }; class ConcreteStateA : public AbstractState { void Handle(Context* p) { cout << "A....." << endl; } }; class ConcreteStateB : public AbstractState { void Handle(Context* p) { cout << "B....." << endl; } }; class Context { public: Context(AbstractState* pstate) : pstate(pstate) {} void Requst() { if (pstate) { pstate->Handle(this); } } void ChangeState(AbstractState* pstate) { this->pstate = pstate; } private: AbstractState* pstate; }; int main() { AbstractState* pA = new ConcreteStateA; AbstractState* pB = new ConcreteStateB; Context* pC = new Context(pA); pC->Requst(); pC->ChangeState(pB); pC->Requst(); return 0; }
优点
-
单一职责原则: 将与特定状态相关的代码放在单独的类中
-
开闭原则: 无需修改已有状态类和上下文就能引入新状态
-
通过消除臃肿的状态机条件语句简化上下文代码
缺点
-
如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作



