备忘录模式(Memento Pattern)又称为快照模式(Snapshot Pattern)或令牌模式(Token Pattern),是指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态,属于行为型模式。
在软件系统中,备忘录模式可以为我们提供一种“后悔药”的机制,他通过存储系统各个历史状态的快照,使得我们可以在任意时刻将系统回滚到某一个历史状态。
备忘录模式本质是从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memento)独立,且存储信息的实体交由管理类(Caretaker)管理,则可以通过为管理类扩展额外的功能对存储信息进行扩展操作(比如增加历史快照功能)。
1、git的版本管理
2、游戏的存档
1、需要保存历史快照的场景;
2、希望在对象之外保存状态,且除了自己其他类对象无法访问状态保存具体内容。
从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.提供状态回滚功能;
缺点:
消耗资源:如果需要保存的状态过多时,每一次保存都会消耗很多内存。
备忘录模式