行为性模式-备忘录模式
生产环境投产时为防止将本地或测试环境配置提交到线上会将配置文件单独抽离出来放到线上,投产之后如果发现有问题代码需要回滚至上个版本,配置文件也需要恢复到上个版本。本文使用备忘录模式来模拟配置文件回滚操作。
uml类图
配置文件(ConfigFile)
private String versionNo;
private String author;
private String content;
private Date date;
备忘录(ConfigMementno)
引入ConfigFile属性,后续记录者类和管理者类操作备忘录类,不会对原配置文件类产生影响
private ConfigFile configFile;
记录者(ConfigOriginator)
引入ConfigFile属性,操作备忘录类
public class ConfigOriginator {
private ConfigFile configFile;
public ConfigFile getConfigFile() {
return configFile;
}
public void setConfigFile(ConfigFile configFile) {
this.configFile = configFile;
}
public ConfigMementno saveMementno() {
return new ConfigMementno(this.configFile);
}
public void getMementno(ConfigMementno configMementno) {
this.configFile = configMementno.getConfigFile();
}
}
管理者(Admin)
增加、回退、前进、回去特定版本操作
public class Admin {
private List<ConfigMementno> configMementnoList = new ArrayList<>();
private Map<String, ConfigMementno> configMementnoMap = new ConcurrentHashMap<>();
private int curIdx = 0;
public void append(ConfigMementno configMementno) {
configMementnoList.add(configMementno);
configMementnoMap.put(configMementno.getConfigFile().getVersionNo(), configMementno);
curIdx++;
}
public ConfigMementno undo() {
if (--curIdx <= 0) {
return configMementnoList.get(0);
}
return configMementnoList.get(curIdx);
}
public ConfigMementno redo() {
if (++curIdx >= configMementnoList.size()) {
return configMementnoList.get(configMementnoList.size() - 1);
}
return configMementnoList.get(curIdx);
}
public ConfigMementno get(String version) {
return configMementnoMap.get(version);
}
}
测试类
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test
public void test() {
ConfigOriginator configOriginator = new ConfigOriginator();
Admin admin = new Admin();
configOriginator.setConfigFile(new ConfigFile("1001","leilei","哈哈",new Date()));
admin.append(configOriginator.saveMementno());
configOriginator.setConfigFile(new ConfigFile("1002","leilei","嘿嘿",new Date()));
admin.append(configOriginator.saveMementno());
configOriginator.setConfigFile(new ConfigFile("1003","leilei","嘻嘻",new Date()));
admin.append(configOriginator.saveMementno());
configOriginator.setConfigFile(new ConfigFile("1004","leilei","呜呜",new Date()));
admin.append(configOriginator.saveMementno());
configOriginator.getMementno(admin.undo());
logger.info("历史配置文件(回滚){}:" + JSON.toJSONString(configOriginator.getConfigFile()));
configOriginator.getMementno(admin.undo());
logger.info("历史配置文件(回滚){}:" + JSON.toJSONString(configOriginator.getConfigFile()));
configOriginator.getMementno(admin.redo());
logger.info("历史配置文件(前进){}:" + JSON.toJSONString(configOriginator.getConfigFile()));
configOriginator.getMementno(admin.get("1001"));
logger.info("历史配置文件(前进){}:" + JSON.toJSONString(configOriginator.getConfigFile()));
}
}
测试结果
com.leilei.design.mementno.test.ApiTest
17:37:11.395 [main] INFO c.l.design.mementno.test.ApiTest - 历史配置文件(回滚){}:{"author":"leilei","content":"呜呜","date":1726652231323,"versionNo":"1004"}
17:37:11.398 [main] INFO c.l.design.mementno.test.ApiTest - 历史配置文件(回滚){}:{"author":"leilei","content":"嘻嘻","date":1726652231323,"versionNo":"1003"}
17:37:11.398 [main] INFO c.l.design.mementno.test.ApiTest - 历史配置文件(前进){}:{"author":"leilei","content":"呜呜","date":1726652231323,"versionNo":"1004"}
17:37:11.399 [main] INFO c.l.design.mementno.test.ApiTest - 历史配置文件(前进){}:{"author":"leilei","content":"哈哈","date":1726652231322,"versionNo":"1001"}
Process finished with exit code 0