备忘录模式(Memento)


简介

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

应用场景

  • 必须保存一个对象在某时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态;
  • 如果一个接口让其它对象直接得到这些状态,将会暴露对象的实现细节并且破坏对象的封装性;

结构图(UML图)


备忘录(Memento)

  • 存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态;
  • 防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者(caretaker)只能看到备忘录的窄接口(它只能将备忘录传递给其它对象)。相反,原发器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想情况只允许生成备忘录那个原发器访问本备忘录;

原发器(Originator)

  • 创建一个备忘录,记录它的当前时刻得内部状态;
  • 使用备忘录恢复内部状态;

管理者(caretaker)

  • 负责保存好备忘录;
  • 不能对备忘录的内容进行操作或者检查;

代码实现

黑盒模式

将Originator声明为Memnto的友元类,Memnto接口声明为私有

#include <iostream>
#include <string>
#include <vector>

using namespace std;

#define DELETE(pointer) delete (pointer); (pointer)=nullptr

class Originator;

class Memento // 备忘录类
{
public:
	~Memento(){}
	// 提供窄接口,以供管理者类Caretaker调用
private: // 所有接口和变量声明为私有,目的是为了只提供给产生这个备忘录的原发器Originator调用,其它接口无法直接调用
	friend Originator; // 目的是为了访问Memnto的private和protected成员函数和成员变量
	string state;
	Memento(string state) :state(state) {}
	const string getState() const { return state; }
	void setState(string state) { this->state = state; }
};

class Originator // 原发器类
{
	string state;
public:
	Originator(string state) :state(state){}
	Memento* createMemento() { return new Memento(state); } // 返回对象state当前状态
	void setMemento(Memento *memento) { state = memento->getState(); } // 设置对象state返回某一时刻状态
	void changeState(string state) { this->state = state; } // 对象state的状态发生改变后需要保存
	const void showState()const { cout << "state==" << state << endl; }
};

class Caretaker // 管理者类
{
	vector<Memento*> mementos; // 不需要在参数列表初始化
	Originator *originator;
public:
	Caretaker(Originator *originator) : originator(originator){}
	~Caretaker() { // 析构时手动删除vector容器指针指向的内存
		for (auto it = mementos.begin(); it != mementos.end(); ++it) {
			if ((*it) != nullptr) {
				DELETE (*it);
			}
		}
	}
	void save(Memento *memento) { mementos.push_back(memento); } // 记录备忘录某一时刻的状态
	void undo(int index) { originator->setMemento(mementos.at(index)); } // 返回备忘录某个时刻index的状态
};

void doMementoPattern()
{
	string state{ "初始状态" };
	Originator *originator = new Originator(state);
	Caretaker *caretaker = new Caretaker(originator);
	caretaker->save(originator->createMemento()); // 保存初始状态
	originator->showState(); // 打印初始状态

	originator->changeState(string{ "状态1" }); // 状态发生改变1
	caretaker->save(originator->createMemento());
	originator->showState();

	originator->changeState(string{ "状态2" }); // 状态发生改变2
	caretaker->save(originator->createMemento());
	originator->showState();
	
	caretaker->undo(0); // 返回到最初状态
	originator->showState();

	DELETE(caretaker);
	DELETE(originator);
}

#include <iostream>

extern void doMementoPattern();

int main()
{
	doMementoPattern();

	system("pause");
	return 1;
}

白盒模式

将Memnto接口声明为公有

#include <iostream>
#include <string>
#include <vector>

using namespace std;

#define DELETE(pointer) delete (pointer); (pointer)=nullptr

class Memento // 备忘录类
{
	string state;
public:
	Memento(string state) :state(state) {}
	const string getState() const { return state; }
	void setState(string state) { this->state = state; }
};

class Originator // 原发器类
{
	string state;
public:
	Originator(string state) :state(state){}
	Memento* createMemento() { return new Memento(state); } // 返回对象state当前状态
	void setMemento(Memento *memento) { state = memento->getState(); } // 设置对象state返回某一时刻状态
	void changeState(string state) { this->state = state; } // 对象state的状态发生改变后需要保存
	const void showState()const { cout << "state==" << state << endl; }
};

class Caretaker // 管理者类
{
	vector<Memento*> mementos; // 不需要在参数列表初始化
	Originator *originator;
public:
	Caretaker(Originator *originator) : originator(originator){}
	~Caretaker() { // 析构时手动删除vector容器指针指向的内存
		for (auto it = mementos.begin(); it != mementos.end(); ++it) {
			if ((*it) != nullptr) {
				DELETE (*it);
			}
		}
	}
	void save(Memento *memento) { mementos.push_back(memento); } // 记录备忘录某一时刻的状态
	void undo(int index) { originator->setMemento(mementos.at(index)); } // 返回备忘录某个时刻index的状态
};

void doMementoPattern()
{
	string state{ "初始状态" };
	Originator *originator = new Originator(state);
	Caretaker *caretaker = new Caretaker(originator);
	caretaker->save(originator->createMemento()); // 保存初始状态
	originator->showState(); // 打印初始状态

	originator->changeState(string{ "状态1" }); // 状态发生改变1
	caretaker->save(originator->createMemento());
	originator->showState();

	originator->changeState(string{ "状态2" }); // 状态发生改变2
	caretaker->save(originator->createMemento());
	originator->showState();
	
	caretaker->undo(0); // 返回到最初状态
	originator->showState();

	DELETE(caretaker);
	DELETE(originator);
}

#include <iostream>

extern void doMementoPattern();

int main()
{
	doMementoPattern();

	system("pause");
	return 1;
}

优缺点

优点

  • 提供某种状态(实际是对象)的回退和前进功能;
  • 实现了状态的封装,客户不需要关注细节即可实现回退等功能;

缺点

  • 如果保存的状态很多,也就是几十个瞬间的状态,当状态对象内存很大时,将会非常耗内存;
  • 每保存一次,就会发生一次对象深拷贝,占用不少CPU资源,需要仔细考虑是否需要这么多备忘录(备份);

总结

备忘录模式核心在于保存一个对象某个时刻部分或者全部状态,以便客户返回时可以取消撤回那个时刻的状态。也就是说,核心思想是保存一个对象状态,当状态改变后用保存的对象赋值给当前对象即可。其实现跟原型模式不同,原型模式主要是对整个对象的克隆,无法做到部分克隆以及接口对所有客户开放,破坏开闭原则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值