//---------------------------15/04/27----------------------------
//Memento 备忘录模式----对象行为型模式
/*
1:意图:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可讲该对象
恢复到原先保存的状态。
2:别名:
Token
3:动机:
4:适用性:
1>必须保存一个对象在某一个时刻的状态,这样以后需要时它才能恢复到先前的状态。
2>如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
5:结构:
Caretaker:
Originator:- - - - - - - - >Memento:<---------memento
SetMemento(Memento m) GetState()
{ state = m->GetState()} SetState()
CreateMemento() state
{ retrun new Memento(state)}
state
6:参与者:
1>Memento:
1)备忘录存储原发器的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
2)防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者接口只能看到备忘录的窄
接口--它只能讲备忘录传递给其他对象。相反,原发器能看到一个宽接口,允许它访问返回到先前状态
所需的所有数据。
2>Originator
1)原发器创建一个备忘录,用以纪录当前时刻它的内部状态。
2)使用备忘录恢复内部状态。
3>Caretaker
1)负责保存好备忘录。
2)不能对备忘录的内容进行操作或检查。
7:协作:
1>管理器向原发器请求一个备忘录,保存一段时间后,将其送回原发器。
2>备忘录时被动的。只有创建备忘录的原发器会对他的状态进行赋值和检索。
8:效果:
1>优点:
1)保护封装边界:
使用备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息。
2)简化了原发器:
让客户来管理它们请求的状态会简化原发器,并且似的客户工作结束时无需通知原发器。
2>缺点:
1)使用备忘录可能代价很高:
如果原发器在生产备忘录时必须拷贝并存储大量的信息,或者客户非常频繁地创建备忘录和恢复原发器
状态,可能会导致非常大的开销。
2)维护备忘录的潜在代价:
管理器负责删除它所维护的备忘录,然后管理器不知道备忘录中有多少个状态。因此当存储备忘录时,
一个本来很小的管理器,可能会产生大量的存储开销。
3>定义窄接口和宽接口:
在一些语言中可能难以保证只有原发器可以访问备忘录的状态。
9:实现:
1>语言支持:
备忘录有两个接口:一个为原发器所使用的宽接口,一个为其他对象所使用的窄接口。
在c++可以声明Originator为Memento的一个友元,并使用Memento宽接口为私有的,把窄接口声明为公有。
2>存储增量式改变:
如果备忘录的创建及其返回的顺序是可预测的,备忘录可以仅存储原发器内部状态的增量改变。
10:代码示例: */
class Graphic;
//Caretaker,提供操作
class MoveCommand
{
public:
MoveCommand(Graphic* target,
const Point& delta);
void Execute();
void Unexecute();
private:
ConstraintSolverMemento* _state;
Point _delta;
Graphic* _target;
};
//原发器:提供创建,保存,撤销操作
class ConstraintSolver
{
public:
static ConstraintSolver* Instance();
void Solve();
void AddConstraint(Graphic* startConnection, Graphic* endConnection);
void RemoveConstaint(Graphic* startConnection, Graphic* endConnection);
ConstraintSolverMemento* CreateMemento();
void SetMemento(ConstraintSolverMemento*);
private:
};
//备忘录
class ConstraintSolverMemento
{
public:
virtual ~ConstraintSolverMemento();
private:
friend class ConstraintSolver;
ConstraintSolverMemento();
//...还有一些state
};
//使用原发器创建一个备忘录,保存起来,然后做别的操作
void MoveCommand::Execute()
{
ConstraintSolver* solver = ConstraintSolver::Instance();
_state = solver->CreateMemento();
_target->Move(_delta_);
solver->Solve();
}
//使用之前存储的备忘录来恢复之前的状态。
void MoveCommand::Unexecute()
{
ConstraintSolver* solver = ConstraintSolver::Instance();
_target->Move(-_delta);
solver->SetMemento(_state);
solver->Solve();
}
//这个例子没法恢复两次以上状态,如果要恢复两次以上,必须使用数组或链表把一个个备忘录存储起来。