GoF原文
Without violating encapsulation,capture and externalize an object’s internal state so that the object can be restored to this state later.
Memento design pattern is used when we want to save the state of an object so that we can restore later on.
备忘录模式的应用场景
对于程序员来说,可能天天都在使用备忘录模式,比如我们每天使用的Git、SVN都可以提供一种代码版本撤回的功能。
还有一个比较贴切的现实场景就是游戏的存档功能,通过将游戏当前进度存储到本地文件系统或数据库中,使得下次继续游戏时,玩家可以从之前的位置继续进行。
备忘录模式主要适用于以下应用场景。
(1)需要保存历史快照的场景。
(2)希望在对象之外保存状态,且除了自己,其他类对象无法访问状态保存的具体内容。
Originator is the object whose state needs to be saved and restored and it uses an inner class to save the state of Object. The inner class is called Memento and it’s private, so that it can’t be accessed from other objects.
Caretaker is the helper class that is responsible for storing and restoring the Originator’s state through Memento object. Since Memento is private to Originator, Caretaker can’t access it and it’s stored as an Object within the caretaker.
Originator Class
[ 美 /əˈrɪdʒɪneɪtər/] 创始人
public class A1_FileWriterUtil {
private String fileName;
private StringBuilder content;
public A1_FileWriterUtil(String file){
this.fileName=file;
this.content=new StringBuilder();
}
@Override
public String toString(){
return this.content.toString();
}
public void write(String str){
content.append(str);
}
public Memento save(){
return new Memento(this.fileName,this.content);
}
public void undoToLastSave(Object obj){
Memento memento = (Memento) obj;
this.fileName= memento.fileName;
this.content=memento.content;
}
private class Memento{
private String fileName;
private StringBuilder content;
public Memento(String file, StringBuilder content){
this.fileName=file;
//notice the deep copy so that Memento and FileWriterUtil content variables don't refer to same object
this.content=new StringBuilder(content);
}
}
}
个人理解:
save 就是:创建一个Memeto对象,把当前对象状态存储到Memeto对象里,返回Memeto对象到外面储存起来
undoToLastSave就是:把储存的Memeto对象拿进来,把当前对象的状态换成Memeto对象储存的值。
Caretaker 就是干存储Memeto对象,提供Memeto对象的活
Caretaker Class
[ 美 /ˈkerteɪkər/] 守护者
public class A2_FileWriterCaretaker {
private Object obj;
public void save(A1_FileWriterUtil fileWriter){
this.obj=fileWriter.save();
}
public void undo(A1_FileWriterUtil fileWriter){
fileWriter.undoToLastSave(obj);
}
}
Example Test Class
public static void main(String[] args) {
A2_FileWriterCaretaker caretaker = new A2_FileWriterCaretaker();
A1_FileWriterUtil fileWriter = new A1_FileWriterUtil("data.txt");
fileWriter.write("First Set of Data ");
System.out.println(fileWriter);
// lets save the file
caretaker.save(fileWriter);
//now write something else
fileWriter.write("Second Set of Data ");
//checking file contents
System.out.println(fileWriter);
//lets undo to last save
caretaker.undo(fileWriter);
//checking file content again
System.out.println(fileWriter);
}
结果
First Set of Data
First Set of Data Second Set of Data
First Set of Data
if Originator object has properties that are not immutable, we should use deep copy or cloning to avoid data integrity issue like I have used in above example.
如果Originator对象的属性是可变的,我们应该使用deep copy或cloning 来避免数据完整性问题,就像我在上面的例子中使用的那样。
We can use Serialization to achieve memento pattern implementation that is more generic rather than Memento pattern where every object needs to have it’s own Memento class implementation.
我们可以使用序列化来实现更通用的memento模式实现,而不是每个对象都需要有自己的memento类实现的memento模式。
One of the drawback is that if Originator object is very huge then Memento object size will also be huge and use a lot of memory.
缺点之一是,如果Originator对象非常大,那么Memento对象的大小也会非常大,并使用大量内存。
备忘录模式生活中的例子:
一个最好的现实例子是文本编辑器,我们可以随时保存它的数据,并使用撤销来恢复它到以前保存的状态。
在JDK源码里一顿找,目前为止还是没找到具体的应用,包括在MyBatis中也没有找到对应的源码。在Spring的Webflow源码中找到一个StateManageableMessageContext接口
public interface StateManageableMessageContext extends MessageContext {
public Serializable createMessagesMemento();
public void restoreMessages(Serializable messagesMemento);
public void setMessageSource(MessageSource messageSource);
}
我们看到有一个createMessagesMemento()方法,创建一个消息备忘录。