趣文网 > 作文大全

重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中 配置文件回滚场景」

2020-12-02 04:20:01
相关推荐

作者:小傅哥博客:https://bugstack.cn

沉淀、分享、成长,让自己和他人都能有所收获!

目录

一、前言二、开发环境三、备忘录模式介绍四、案例场景模拟五、备忘录模式记录配置文件版本信息1. 工程结构2. 代码实现3. 测试验证六、总结

一、前言

实现不了是研发的借口?

实现不了,有时候是功能复杂度较高难以实现,有时候是工期较短实现不完。而编码的行为又是一个不太好量化的过程,同样一个功能每个人的实现方式不一样,遇到开发问题解决问题的速度也不一样。除此之外还很不好给产品解释具体为什么要这个工期时间,这就像盖楼的图纸最终要多少水泥砂浆一样。那么这时研发会尽可能的去通过一些经验,制定流程规范、设计、开发、评审等,确定一个可以完成的时间范围,又避免风险的时间点后。再被压缩,往往会出一些矛盾点,能压缩要解释为什么之前要那么多时间,不能压缩又有各方不断施加的压力。因此有时候不一定是借口,是要考虑如何让整个团队健康的发展。

鼓励有时比压力要重要!

在学习的过程中,很多时候我们听到的都是,你要怎样,怎样,你瞧瞧谁谁谁,哪怕今天听不到这样的声音了,但因为曾经反复听到过而导致内心抗拒。虽然也知道自己要去学,但是很难坚持,学着学着就没有了方向,看到还有那么多不会的就更慌了,以至于最后心态崩了,更不愿意学。其实程序员的压力并不小,想成长几乎是需要一直的学习,就像似乎再也不敢说精通java了一样,知识量实在是随着学习的深入,越来越深,越来越广。所以需要,开心学习,快乐成长!

临阵的你好像一直很着急!

经常的听到;老师明天就要了你帮我弄弄吧、你给我写一下完事我就学这次着急、现在这不是没时间学吗快给我看看。其实看到的类似的还有很多,很纳闷你的着急怎么来的,不太可能,人在家中坐,祸从天上落。老师怎么就那个时间找你了,老板怎么就今天管你要了,还不是日积月累你没有学习,临时抱佛脚乱着急!即使后来真的有人帮你了,但最好不要放松,要尽快学会,躲得过初一还有初二呢!

二、开发环境

JDK 1.8Idea + Maven涉及工程一个,可以通过关注「公众号」:bugstack虫洞栈,回复源码下载获取(打开获取的链接,找到序号18)

三、备忘录模式介绍

备忘录模式,图片来自 refactoringguru.cn备忘录模式是以可以恢复或者说回滚,配置、版本、悔棋为核心功能的设计模式,而这种设计模式属于行为模式。在功能实现上是以不破坏原对象为基础增加备忘录操作类,记录原对象的行为从而实现备忘录模式。

这个设计在我们平常的生活或者开发中也是比较常见的,比如:后悔药、孟婆汤(一下回滚到0),IDEA编辑和撤销、小霸王游戏机存档。当然还有我们非常常见的Photoshop,如下;

Photoshop 历史记录四、案例场景模拟

场景模拟;系统发布上线配置回滚「在本案例中我们模拟系统在发布上线的过程中记录线上配置文件用于紧急回滚」

在大型互联网公司系统的发布上线一定是易用、安全、可处理紧急状况的,同时为了可以隔离线上和本地环境,一般会把配置文件抽取出来放到线上,避免有人误操作导致本地的配置内容发布出去。同时线上的配置文件也会在每次变更的时候进行记录,包括;版本号、时间、MD5、内容信息和操作人。

在后续上线时如果发现紧急问题,系统就会需要回滚操作,如果执行回滚那么也可以设置配置文件是否回滚。因为每一个版本的系统可能会随着带着一些配置文件的信息,这个时候就可以很方便的让系统与配置文件一起回滚操作。

我们接下来就使用备忘录模式,模拟如何记录配置文件信息。实际的使用过程中还会将信息存放到库中进行保存,这里暂时只是使用内存记录。

五、备忘录模式记录配置文件版本信息

备忘录的设计模式实现方式,重点在于不更改原有类的基础上,增加备忘录类存放记录。可能平时虽然不一定非得按照这个设计模式的代码结构来实现自己的需求,但是对于功能上可能也完成过类似的功能,记录系统的信息。

除了现在的这个案例外,还可以是运营人员在后台erp创建活动对信息的记录,方便运营人员可以上下修改自己的版本,而不至于因为误操作而丢失信息。

1. 工程结构

itstack-demo-design-17-00└── src ├── main │ └── java │ └── org.itstack.demo.design │ ├── Admin.java │ ├── ConfigFile.java │ ├── ConfigMemento.java │ └── ConfigOriginator.java └── test └── java └── org.itstack.demo.design.test └── ApiTest.java「备忘录模式模型结构」

备忘录模式模型结构以上是工程结构的一个类图,其实相对来说并不复杂,除了原有的配置类(ConfigFile)以外,只新增加了三个类。ConfigMemento:备忘录类,相当于是对原有配置类的扩展ConfigOriginator:记录者类,获取和返回备忘录类对象信息Admin:管理员类,用于操作记录备忘信息,比如你一些列的顺序执行了什么或者某个版本下的内容信息2. 代码实现

2.1 配置信息类

publicclassConfigFile{private String versionNo; // 版本号private String content; // 内容private Date dateTime; // 时间private String operator; // 操作人// ...get/set}配置类可以是任何形式的,这里只是简单的描述了一个基本的配置内容信息。2.2 备忘录类

publicclassConfigMemento{private ConfigFile configFile;publicConfigMemento(ConfigFile configFile){this.configFile = configFile; }public ConfigFile getConfigFile(){return configFile; }publicvoidsetConfigFile(ConfigFile configFile){this.configFile = configFile; }}备忘录是对原有配置类的扩展,可以设置和获取配置信息。2.3 记录者类

publicclassConfigOriginator{private ConfigFile configFile;public ConfigFile getConfigFile(){return configFile; }publicvoidsetConfigFile(ConfigFile configFile){this.configFile = configFile; }public ConfigMemento saveMemento(){returnnew ConfigMemento(configFile); }publicvoidgetMemento(ConfigMemento memento){this.configFile = memento.getConfigFile(); }}记录者类除了对ConfigFile配置类增加了获取和设置方法外,还增加了保存saveMemento()、获取getMemento(ConfigMemento memento)。saveMemento:保存备忘录的时候会创建一个备忘录信息,并返回回去,交给管理者处理。getMemento:获取的之后并不是直接返回,而是把备忘录的信息交给现在的配置文件this.configFile,这部分需要注意。2.4 管理员类

publicclassAdmin{privateint cursorIdx = 0;private List mementoList = new ArrayList();private Map mementoMap = new ConcurrentHashMap();publicvoidappend(ConfigMemento memento){ mementoList.add(memento); mementoMap.put(memento.getConfigFile().getVersionNo(), memento); cursorIdx++; }public ConfigMemento undo(){if (--cursorIdx <= 0) return mementoList.get(0);return mementoList.get(cursorIdx); }public ConfigMemento redo(){if (++cursorIdx > mementoList.size()) return mementoList.get(mementoList.size() - 1);return mementoList.get(cursorIdx); }public ConfigMemento get(String versionNo){return mementoMap.get(versionNo); }}在这个类中主要实现的核心功能就是记录配置文件信息,也就是备忘录的效果,之后提供可以回滚和获取的方法,拿到备忘录的具体内容。同时这里设置了两个数据结构来存放备忘录,实际使用中可以按需设置。List、Map。最后是提供的备忘录操作方法;存放(append)、回滚(undo)、返回(redo)、定向获取(get),这样四个操作方法。3. 测试验证

3.1 编写测试类

@Testpublicvoidtest(){ Admin admin = new Admin(); ConfigOriginator configOriginator = new ConfigOriginator(); configOriginator.setConfigFile(new ConfigFile("1000001", "配置内容A=哈哈", new Date(), "小傅哥")); admin.append(configOriginator.saveMemento()); // 保存配置 configOriginator.setConfigFile(new ConfigFile("1000002", "配置内容A=嘻嘻", new Date(), "小傅哥")); admin.append(configOriginator.saveMemento()); // 保存配置 configOriginator.setConfigFile(new ConfigFile("1000003", "配置内容A=么么", new Date(), "小傅哥")); admin.append(configOriginator.saveMemento()); // 保存配置 configOriginator.setConfigFile(new ConfigFile("1000004", "配置内容A=嘿嘿", new Date(), "小傅哥")); admin.append(configOriginator.saveMemento()); // 保存配置 // 历史配置(回滚) configOriginator.getMemento(admin.undo()); logger.info("历史配置(回滚)undo:{}", JSON.toJSONString(configOriginator.getConfigFile())); // 历史配置(回滚) configOriginator.getMemento(admin.undo()); logger.info("历史配置(回滚)undo:{}", JSON.toJSONString(configOriginator.getConfigFile())); // 历史配置(前进) configOriginator.getMemento(admin.redo()); logger.info("历史配置(前进)redo:{}", JSON.toJSONString(configOriginator.getConfigFile())); // 历史配置(获取) configOriginator.getMemento(admin.get("1000002")); logger.info("历史配置(获取)get:{}", JSON.toJSONString(configOriginator.getConfigFile()));}这个设计模式的学习有一部分重点是体现在了单元测试类上,这里包括了四次的信息存储和备忘录历史配置操作。通过上面添加了四次配置后,下面分别进行操作是;回滚1次、再回滚1次,之后向前进1次,最后是获取指定的版本配置。具体的效果可以参考测试结果。3.2 测试结果

23:12:09.512 [main] INFO org.itstack.demo.design.test.ApiTest - 历史配置(回滚)undo:{"content":"配置内容A=嘿嘿","dateTime":159209829432,"operator":"小傅哥","versionNo":"1000004"}23:12:09.514 [main] INFO org.itstack.demo.design.test.ApiTest - 历史配置(回滚)undo:{"content":"配置内容A=么么","dateTime":159209829432,"operator":"小傅哥","versionNo":"1000003"}23:12:09.514 [main] INFO org.itstack.demo.design.test.ApiTest - 历史配置(前进)redo:{"content":"配置内容A=嘿嘿","dateTime":159209829432,"operator":"小傅哥","versionNo":"1000004"}23:12:09.514 [main] INFO org.itstack.demo.design.test.ApiTest - 历史配置(获取)get:{"content":"配置内容A=嘻嘻","dateTime":159320989432,"operator":"小傅哥","versionNo":"1000002"}Process finished with exit code 0从测试效果上可以看到,历史配置按照我们的指令进行了回滚和前进,以及最终通过指定的版本进行获取,符合预期结果。六、总结

此种设计模式的方式可以满足在不破坏原有属性类的基础上,扩充了备忘录的功能。虽然和我们平时使用的思路是一样的,但在具体实现上还可以细细品味,这样的方式在一些源码中也有所体现。在以上的实现中我们是将配置模拟存放到内存中,如果关机了会导致配置信息丢失,因为在一些真实的场景里还是需要存放到数据库中。那么此种存放到内存中进行回复的场景也不是没有,比如;Photoshop、运营人员操作ERP配置活动,那么也就是即时性的一般不需要存放到库中进行恢复。另外如果是使用内存方式存放备忘录,需要考虑存储问题,避免造成内存大量消耗。设计模式的学习都是为了更好的写出可扩展、可管理、易维护的代码,而这个学习的过程需要自己不断的尝试实际操作,理论的知识与实际结合还有很长一段距离。切记多多上手!

bugstack虫洞栈

沉淀、分享、成长,让自己和他人都能有所收获!

作者小傅哥多年从事一线互联网Java开发,从19年开始编写工作和学习历程的技术汇总,旨在为大家提供一个较清晰详细的核心技能学习文档。如果本文能为您提供帮助,请给予支持(关注、点赞、分享)!

阅读剩余内容
网友评论
相关内容
延伸阅读
小编推荐

大家都在看

写炸酱面的作文 这次考试作文 丢失作文 小馄饨作文 童眼看世界作文 我的学习好方法作文 军训趣事作文600字 小学生作文菊花 寻找春天作文500字 磨刀不误砍柴工作文 消防安全作文400字 五年级作文给妈妈的一封信 参观水母馆作文 吹泡泡作文二年级 我爱我的家乡作文 我的未来在哪里作文 我的家乡昆明作文 观雨作文500字 时代少年团作文 作文开头优美句子20字 一篇关于母亲的作文 关于体育活动的作文 不平凡的一天作文600字 乡情作文600字记叙文 任务型驱动作文怎么写 不要盲从的作文 运用托物言志的作文 爸爸传记作文 为自己喝彩作文 二元对立作文