type
status
date
slug
summary
tags
category
icon
password
一、定义

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后需要的时候,能将该对象恢复到原先的状态
二、示例:
模拟场景: 1、git的提交记录,不仅能查看自己的提交记录,并且还能回滚到之前的版本
2、在⼤型互联⽹公司系统的发布上线都会记录发版的信息,包括;版本号、时间、MD5、内容信息和操作⼈。在后续上线时如果发现紧急问题,系统就会需要回滚操作,如果执⾏回滚那么也可以设置配置⽂件是否回滚。
我们接下来就使⽤备忘录模式,模拟如何记录配置⽂件信息。实际的使⽤过程中还会将信息存放到库中进⾏保存,这⾥暂时只是使⽤内存记录
备忘录模式
备忘录配置文件
package com.qf.design.behavior.memorandum; import java.util.Date; /** * 备忘录配置文件 */ public class ConfigFile { private String versionNo;//版本号 private String content;//内容 private Date date; //日期 private String oprator;//操作人 public ConfigFile(String versionNo, String content, Date date, String oprator) { this.versionNo = versionNo; this.content = content; this.date = date; this.oprator = oprator; } public String getVersionNo() { return versionNo; } public void setVersionNo(String versionNo) { this.versionNo = versionNo; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getOprator() { return oprator; } public void setOprator(String oprator) { this.oprator = oprator; } }
备忘录类
package com.qf.design.behavior.memorandum; /** * 备忘录类 */ public class ConfigMemento { private ConfigFile configFile; public ConfigMemento(ConfigFile configFile){ this.configFile=configFile; } public ConfigFile getConfigFile(){ return configFile; } public void setConfigFile(ConfigFile configFile){ this.configFile=configFile; } }
备忘录操作人员:
package com.qf.design.behavior.memorandum; public class ConfigOperator { private ConfigMemento configMemento; private ConfigFile configFile; public ConfigMemento getConfigMemento() { return configMemento; } public void setConfigMemento(ConfigMemento configMemento) { this.configMemento = configMemento; } public ConfigFile getConfigFile(){ return configFile; } public void setConfigFile(ConfigFile configFile){ this.configFile=configFile; } }
管理后台
package com.qf.design.behavior.memorandum; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Admin { private int cursorinx=0; private List<ConfigMemento> configMementoList=new ArrayList<>(); private Map<String,ConfigMemento> configMementoMap=new HashMap<>(); public void append(ConfigMemento configMemento){ configMementoList.add(configMemento); configMementoMap.put(configMemento.getConfigFile().getVersionNo(),configMemento); cursorinx++; } public ConfigMemento undo(){ if (--cursorinx<=0){ return configMementoList.get(0); } return configMementoList.get(cursorinx); } public ConfigMemento redo(){ if (++cursorinx>=configMementoList.size()){ return configMementoList.get(configMementoList.size()-1); } return configMementoList.get(cursorinx); } public ConfigMemento get(String version){ ConfigMemento configMemento = configMementoMap.get(version); return configMemento; } }
测试:
ApiTest
package com.qf.design.behavior.memorandum; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; public class ApiTest { private static Logger logger= LoggerFactory.getLogger(ApiTest.class); public static void main(String[] args) { Admin admin=new Admin(); ConfigOperator configOperator=new ConfigOperator(); ConfigFile configFile = new ConfigFile("1004001", "配置内容A版本", new Date(), "小王哥"); ConfigMemento configMemento = new ConfigMemento(configFile); configOperator.setConfigFile(configFile); configOperator.setConfigMemento(configMemento); admin.append(configMemento); ConfigFile configFile1 = new ConfigFile("1004002", "配置内容B版本", new Date(), "小王哥"); ConfigMemento configMemento1 = new ConfigMemento(configFile1); configOperator.setConfigFile(configFile1); configOperator.setConfigMemento(configMemento1); admin.append(configMemento1); ConfigFile configFile2 = new ConfigFile("10040013", "配置内容C版本", new Date(), "小王哥"); ConfigMemento configMemento2 = new ConfigMemento(configFile2); configOperator.setConfigFile(configFile2); configOperator.setConfigMemento(configMemento2); admin.append(configMemento2); ConfigFile configFile3 = new ConfigFile("1004004", "配置内容D版本", new Date(), "小王哥"); ConfigMemento configMemento3 = new ConfigMemento(configFile3); configOperator.setConfigFile(configFile3); configOperator.setConfigMemento(configMemento3); admin.append(configMemento3); ConfigMemento redo = admin.undo(); ConfigFile configFile4 = redo.getConfigFile(); logger.info("第一次版本回滚{}", JSON.toJSONString(configFile4)); ConfigMemento redo2 = admin.undo(); ConfigFile configFile5 = redo2.getConfigFile(); logger.info("第二次版本回滚{}", JSON.toJSONString(configFile5)); ConfigMemento redo3 = admin.redo(); ConfigFile configFile6 = redo3.getConfigFile(); logger.info("当前版本{}", JSON.toJSONString(configFile6)); ConfigMemento configMemento4 = admin.get("1004004"); ConfigFile configFile7 = configMemento4.getConfigFile(); logger.info("查看版本1004004{}", JSON.toJSONString(configFile7)); } }

总结: 此种设计模式的⽅式可以满⾜在不破坏原有属性类的基础上,扩充了备忘录的功能。虽然和我们平时使⽤的思路是⼀样的,但在具体实现上还可以细细品味,这样的⽅式在⼀些源码中也有所体现。
在以上的实现中我们是将配置模拟存放到内存中,如果关机了会导致配置信息丢失,因为在⼀些真实的场景⾥还是需要存放到数据库中。那么此种存放到内存中进⾏回复的场景也不是没有,⽐Photoshop、运营⼈员操作ERP配置活动,那么也就是即时性的⼀般不需要存放到库中进⾏恢复。另外如果是使⽤内存⽅式存放备忘录,需要考虑存储问题,避免造成内存⼤量消耗。
- 作者:程序员小舟
- 链接:https://codezhou.top/article/JAVA%E3%80%90%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%91%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章