设计模式--备忘录模式
简介
备忘录模式(Memento Pattern)又称为快照模式(Snapshot Pattern)或令牌模式(Token Pattern),是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态,属于行为型模式。
在软件系统中,备忘录模式可以为我们提供一种“后悔药”的机制,他通过存储系统各个历史状态的快照,使得我们可以在任意时刻将系统回滚到某一个历史状态。
备忘录模式本质是从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memento)独立,且存储信息的实体交由管理类(Caretaker)管理,则可以通过为管理类扩展额外的功能对存储信息进行扩展操作(比如增加历史快照功能)。
备忘录模式的生活场景
1、git的版本管理
2、游戏的存档
备忘录模式适用于以下应用场景:
1、需要保存历史快照的场景;
2、希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存具体内容。
备忘录模式的通用UML类图:
从UML类图中,我们可以看到,备忘录模式主要包含三种角色:
发起人角色(Originator):负责创建一个备忘录,记录自身需要保存的状态;具备状态回滚功能;
备忘录角色(Memento):用于存储Originator的内部状态,且可以防止Originator以外的对象访问;
备忘录管理角色(Caretaker):负责存储,提供管理备忘录(Memento),无法对备忘录内容进行操作和访问。
备忘录模式在源码中的体现
备忘录模式在框架源码中的应用比较少,主要还是需要结合具体的业务场景来使用。
Spring的webflow
源码中StateManageableMessageContext
接口
public interface StateManageableMessageContext extends MessageContext {
Serializable createMessagesMemento();
void restoreMessages(Serializable messagesMemento);
void setMessageSource(MessageSource messageSource);
}
可以看到这里有一个createMessagesMemento()
方法,创建一个消息备忘录。它的实现类:
public class DefaultMessageContext implements StateManageableMessageContext {
private static final Log logger = LogFactory.getLog(DefaultMessageContext.class);
private MessageSource messageSource;
@SuppressWarnings("serial")
private Map<Object, List<Message>> sourceMessages = new AbstractCachingMapDecorator<Object, List<Message>>(
new LinkedHashMap<Object, List<Message>>()) {
protected List<Message> create(Object source) {
return new ArrayList<>();
}
};
...
public void clearMessages() {
sourceMessages.clear();
}
// implementing state manageable message context
public Serializable createMessagesMemento() {
return new LinkedHashMap<Object, List<Message>>(sourceMessages);
}
@SuppressWarnings("unchecked")
public void restoreMessages(Serializable messagesMemento) {
sourceMessages.putAll((Map<Object, List<Message>>) messagesMemento);
}
public void setMessageSource(MessageSource messageSource) {
if (messageSource == null) {
messageSource = new DefaultTextFallbackMessageSource();
}
this.messageSource = messageSource;
}
...
}
我们看到其主要逻辑就相当于是给Message留一个备用,以备恢复之用。
备忘录模式的优缺点
优点:
1、简化发起人实体类(Originator)职责,隔离状态存储或获取,实现了信息的封装,客户端无需关心状态的保存细节;
2.提供状态回滚功能;
缺点:
消耗资源:如果需要保存的状态过多时,每一次保存都会消耗很多内存。