龙空技术网

游戏的存档功能是如何使用设计模式来实现的,请看备忘录模式详解

cafebabe 787

前言:

而今朋友们对“安卓备忘录源码”大约比较关怀,朋友们都想要知道一些“安卓备忘录源码”的相关资讯。那么小编也在网摘上搜集了一些关于“安卓备忘录源码””的相关内容,希望各位老铁们能喜欢,小伙伴们快快来学习一下吧!

备忘录模式(Memento Pattern)又称为快照模式(Snapshot Pattern)或者令牌模式(Token Pattern),是指在不破坏封装的前提下,捕获一个内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

在软件系统中,备忘录模式为我们提供了一种“后悔药”的机制,它通过存储系统各个历史状态的快照,使得我们可以在任意时刻将系统回滚到某一个历史状态。

一、备忘录模式的应用场景

我们机会天天都在使用备忘录模式,比如使用Git、SVN提供一种代码版本撤回的功能。还有游戏的存档功能,通过将游戏当前进度存储到本地文件系统或数据库中,使得下次继续游戏时,玩家可以从之前的位置继续进行。

备忘录模式适用于以下两个场景:

需要保存历史快照的场景;希望在对象之外保存状态,且除了自己其它类对象无法访问状态保存具体内容。

备忘录模式主要包含三种角色:

发起人角色(Orgainator):负责创建一个备忘录,记录自身需要保存的状态,具备状态回滚功能;备忘录角色(Memento):用于存储发起人的内部状态,且可以防止发起人以外的对象进行访问;备忘录管理员(Caretaker):负责存储,提供管理备忘录,无法对备忘录内容进行操作和访问。1.1 利用压栈管理落地备忘录模式

我们在网页上写文章或者博客都使用过富文本编辑器,它会附带草稿箱、撤销等这样的功能。

下面使用代码来实现这样的功能。假设我们需要发布一篇文章,这篇文章的编辑过程需要花很长的时间,编辑的过程中会不停的撤销,保存草稿、修改。首先创建发起人角色编辑器 Editor 类:

public class Editor {    private String title;    private String content;    private String imgs;    public Editor(String title, String content, String imgs) {        this.title = title;        this.content = content;        this.imgs = imgs;    }    public ArticleMemento save2Memento() {        ArticleMemento articleMemento =                new ArticleMemento(this.title, this.content, this.imgs);        return articleMemento;    }    public void undoFromMemento(ArticleMemento articleMemento) {        this.title = articleMemento.getTitle();        this.content = articleMemento.getContent();        this.imgs = articleMemento.getImgs();    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }    public String getImgs() {        return imgs;    }    public void setImgs(String imgs) {        this.imgs = imgs;    }    @Override    public String toString() {        return "Editor{" +                "title='" + title + '\'' +                ", content='" + content + '\'' +                ", imgs='" + imgs + '\'' +                '}';    }}

然后创建备忘录角色 ArticleMemento 类:

public class ArticleMemento {    private String title;    private String content;    private String imgs;    public ArticleMemento(String title, String content, String imgs) {        this.title = title;        this.content = content;        this.imgs = imgs;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }    public String getImgs() {        return imgs;    }    public void setImgs(String imgs) {        this.imgs = imgs;    }    @Override    public String toString() {        return "ArticleMemento{" +                "title='" + title + '\'' +                ", content='" + content + '\'' +                ", imgs='" + imgs + '\'' +                '}';    }}

创建备忘录管理角色草稿箱 DraftBox 类:

public class DraftBox {    private final Stack<ArticleMemento> STACK = new Stack<>();    public ArticleMemento getMemento() {        ArticleMemento articleMemento = STACK.pop();        return articleMemento;    }    public void addMemento(ArticleMemento articleMemento) {        STACK.push(articleMemento);    }}

草稿箱的Stack类是Vector的一个子类,它实现了一个标准的后进先出的栈。

二、备忘录模式在源码中的体现

备忘录模式在框架源码中的应用还是比较少见的,主要还是结合具体的应用场景来使用。spring中的webfolw源码StateManageableMessageContext接口,我们来看它的源码:

public interface StateManageableMessageContext extends MessageContext {	/**	 * Create a serializable memento, or token representing a snapshot of the internal state of this message context.	 * @return the messages memento	 */	public Serializable createMessagesMemento();	/**	 * Set the state of this context from the memento provided. After this call, the messages in this context will match	 * what is encapsulated inside the memento. Any previous state will be overridden.	 * @param messagesMemento the messages memento	 */	public void restoreMessages(Serializable messagesMemento);	/**	 * Configure the message source used to resolve messages added to this context. May be set at any time to change how	 * coded messages are resolved.	 * @param messageSource the message source	 * @see MessageContext#addMessage(MessageResolver)	 */	public 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<Message>();		}	};	/**	 * Creates a new default message context. Defaults to a message source that simply resolves default text and cannot	 * resolve localized message codes.	 */	public DefaultMessageContext() {		init(null);	}	/**	 * Creates a new default message context.	 * @param messageSource the message source to resolve messages added to this context	 */	public DefaultMessageContext(MessageSource messageSource) {		init(messageSource);	}	public MessageSource getMessageSource() {		return messageSource;	}	// implementing message context	public Message[] getAllMessages() {		List<Message> messages = new ArrayList<Message>();		for (List<Message> list : sourceMessages.values()) {			messages.addAll(list);		}		return messages.toArray(new Message[messages.size()]);	}	public Message[] getMessagesBySource(Object source) {		List<Message> messages = sourceMessages.get(source);		return messages.toArray(new Message[messages.size()]);	}	public Message[] getMessagesByCriteria(MessageCriteria criteria) {		List<Message> messages = new ArrayList<Message>();		for (List<Message> sourceMessages : this.sourceMessages.values()) {			for (Message message : sourceMessages) {				if (criteria.test(message)) {					messages.add(message);				}			}		}		return messages.toArray(new Message[messages.size()]);	}	public boolean hasErrorMessages() {		for (List<Message> sourceMessages : this.sourceMessages.values()) {			for (Message message : sourceMessages) {				if (message.getSeverity() == Severity.ERROR) {					return true;				}			}		}		return false;	}	public void addMessage(MessageResolver messageResolver) {		Locale currentLocale = LocaleContextHolder.getLocale();		if (logger.isDebugEnabled()) {			logger.debug("Resolving message using " + messageResolver);		}		Message message = messageResolver.resolveMessage(messageSource, currentLocale);		List<Message> messages = sourceMessages.get(message.getSource());		if (logger.isDebugEnabled()) {			logger.debug("Adding resolved message " + message);		}		messages.add(message);	}	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;	}	// internal helpers	private void init(MessageSource messageSource) {		setMessageSource(messageSource);		// create the 'null' source message list eagerly to ensure global messages are indexed first		this.sourceMessages.get(null);	}	public String toString() {		return new ToStringCreator(this).append("sourceMessages", sourceMessages).toString();	}	private static class DefaultTextFallbackMessageSource extends AbstractMessageSource {		protected MessageFormat resolveCode(String code, Locale locale) {			return null;		}	}}

主要逻辑就相当于是给Message留一个备份,以备恢复之用。

三、备忘录模式的优缺点

优点:

简化发起人职责,隔离状态存储与获取,实现了信息的封装,客户端无需关心状态的保存细节;提供状态回滚功能。

缺点: 消耗资源:如果需要保存的状态过多时,每一次保存都会消耗很多内存。

标签: #安卓备忘录源码