摘要:本文深入浅出的讲述了设计模式中的
备忘录
模式
,
并给出了简单的示例
,
例子浅显易懂
,
并附带源代码。
备忘录模式属于行为型模式,其意图是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将对象恢复到原先保存的状态。有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作,或从错误中恢复过来,需要实现检查点和取消机制,而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到他们先前的状态。但是对象通常封装了其部分或所有的状态信息,使得其状态不能被其他的对象访问。也就不可能在该对象之外保存其状态。而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。
适用性:
l
必须保存一个对象在某一个时刻的状态,这样以后需要时它才能恢复到先前的状态。
l
如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
图
1Memento
的类图
协作关系是:客户端每操作一步
Employee
(原发器)的信息,便产生一个
Memento
对象,并把
Memento
对象发送给
CareTaker
保存,当需要恢复的时候便从
CareTaker
对象中取出
Memento
对象,进行状态的恢复。
参与者:
Memento
(备忘录
Memento
):
备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
防止原发器之外的其他对象访问备忘录,备忘录实际上有两个接口,管理者
CareTaker
只能看到备忘录的窄接口
--
它只能将备忘录传递给其他对象。相反,原生器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情况是只能允许生成备忘录的那个原发器访问本备忘录的内部状态。
Originator(
原发器,如
Employee)
:
原发器创建一个备忘录,用以记录当前时刻它的内部状态。
使用备忘录恢复内部的状态。
CareTaker
(负责人
):
负责保存好备忘录。
不能对备忘录的内容进行操作或检查。
效果:
备忘录模式有以下的一些效果:
1)
保持封装的边界:
使用备忘录可以避免暴露一些只应有原发器管理却又必须存储在原发器之外的信息。该模式把可能很复杂的
Originator
内部信息对其他对象屏蔽起来,从而保持了封装的边界。
2)
它简化了原发器
在其他的保持封装性的设计中,
originator
负责保持客户请求过的内部状态版本。这就把所有存储管理的重任务交给了
Originator
。让客户管理他们请求的状态将会简化
Originator,
并且使得客户工作结束时无需通知原发器。
3)
使用备忘录可能代价很高
如果原发器在生成备忘录时必须拷贝并存储大量的信息,或者客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销。除非封装和恢复
Originator
状态的开销不大,否则该模式可能并不适合。
4)
定义窄接口和宽接口
在一些语言中可能难以保证只有原发器可访问备忘录的状态。
5)
维护备忘录的潜在代价
管理器负责删除它所维护的备忘录。然而
,管理器不知道备忘录中有多少个状态,因此当存储备忘录时,一个本来很小的管理器,可能会产生大量的存储开销。
相关的代码:
Memento
代码:
package
memento;
public
class
Memento{
String
name
;
int
age
;
public
Memento(String name,
int
age){
this
.
name
= name;
this
.
age
= age;
}
}
Employee
模式:
package
memento;
public
class
Employee{
private
String
name
;
private
int
age
;
public
Employee(String aName,
int
aAge){
name
= aName;
age
= aAge;
}
public
void
setName(String aName){
name
= aName;
}
public
void
setAge(
int
aAge){
age
= aAge;
}
public
Memento saveMemento(){
return
new
Memento(
name
,
age
);
}
public
void
restoreMemento(Memento memento){
age
= memento.
age
;
name
= memento.
name
;
}
public
int
getAge(){
return
age
;
}
public
String getName(){
return
name
;
}
}
CareTaker
代码:
package
memento;
import
java.util.Vector;
public
class
CareTaker{
private
Vector
v
;
private
int
current
;
public
CareTaker(){
current
= -1;
v
=
new
Vector();
}
public
void
setMemento(Memento mem){
for
(
int
i =
current
+1;i<
v
.size();i++)
v
.remove(i);
current
++;
v
.add(mem);
}
public
Memento getMemento(){
if
(
current
>0){
current
--;
return
(Memento)
v
.get(
current
);
}
return
null
;
}
}
Client
代码:
package
memento;
public
class
Client{
public
static
void
show(Employee e){
System.
out
.println(
"-----------------------------------"
);
System.
out
.println(
"Name:"
+e.getName());
System.
out
.println(
"Age:"
+ e.getAge());
System.
out
.println(
"-----------------------------------"
);
}
public
static
void
main(String[] args){
Employee e =
new
Employee(
"lili"
,25);
CareTaker ct =
new
CareTaker();
show(e);
ct.setMemento(e.saveMemento());
e.setName(
"litianli"
);
show(e);
ct.setMemento(e.saveMemento());
e.setAge(45);
show(e);
ct.setMemento(e.saveMemento());
//restore
e.restoreMemento(ct.getMemento());
show(e);
e.restoreMemento(ct.getMemento());
show(e);
}
}
总结:备忘录模式保存了对象的内部状态改变信息,提供了撤销和重做动作所需要的所有数据,与
Command
模式比较类似。