40 | 运用学过的设计原则和思想完善之前讲的性能计数器项目(下)
王争
该思维导图由 AI 生成,仅供参考
上一节课中,我们针对版本 1 存在的问题(特别是 Aggregator 类、ConsoleReporter 和 EmailReporter 类)进行了重构优化。经过重构之后,代码结构更加清晰、合理、有逻辑性。不过,在细节方面还是存在一些问题,比如 ConsoleReporter、EmailReporter 类仍然存在代码重复、可测试性差的问题。今天,我们就在版本 3 中持续重构这部分代码。
除此之外,在版本 3 中,我们还会继续完善框架的功能和非功能需求。比如,让原始数据的采集和存储异步执行,解决聚合统计在数据量大的情况下会导致内存吃紧问题,以及提高框架的易用性等,让它成为一个能用且好用的框架。
话不多说,让我们正式开始版本 3 的设计与实现吧!
代码重构优化
我们知道,继承能解决代码重复的问题。我们可以将 ConsoleReporter 和 EmailReporter 中的相同代码逻辑,提取到父类 ScheduledReporter 中,以解决代码重复问题。按照这个思路,重构之后的代码如下所示:
ConsoleReporter 和 EmailReporter 代码重复的问题解决了,那我们再来看一下代码的可测试性问题。因为 ConsoleReporter 和 EmailReporter 的代码比较相似,且 EmailReporter 的代码更复杂些,所以,关于如何重构来提高其可测试性,我们拿 EmailReporter 来举例说明。将重复代码提取到父类 ScheduledReporter 之后,EmailReporter 代码如下所示:
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了如何通过设计原则和思想来完善性能计数器项目。首先,通过代码重构优化,解决了ConsoleReporter和EmailReporter中的代码重复问题,并提高了可测试性。重点讨论了提高EmailReporter的可测试性,通过抽离代码和参数传递来解决时间计算逻辑的问题。文章还详细介绍了功能需求的完善,包括接口统计信息、统计信息显示格式和终端、统计触发方式、统计时间区间和间隔等。最后,提出了版本3中还未实现的功能点,包括被动触发统计的方式、自定义显示终端和显示格式的设计。整体来说,本文通过具体的代码示例和思路分析,展示了如何通过设计原则和思想来不断完善性能计数器项目,为读者提供了一种深入理解和应用设计原则的思路。文章还涉及了性能、扩展性、容错性和通用性等方面的讨论,为读者提供了全面的技术视角。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》,新⼈⾸单¥98
《设计模式之美》,新⼈⾸单¥98
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(46)
- 最新
- 精选
- 李小四设计模式_40: # 作业 导致多个线程的重复统计。 办法:加入进程内的全局变量(注意多线程同步问题)。 # 感想 我个人是Android工程师,客户端的开发默认就要思考一个问题:方法重复调用时(如多次点击某个按钮等)逻辑是否还正常。 25,26,39,40这四节课边听边读反复了好几遍了,因为目的是掌握该掌握的东西,而不是简单地打个卡,所以整个春节期间就卡在这四节课的重复中了,不停地循环听。。。 也有好处:我反倒对这几节内容非常熟悉了,有两点感受较深: 1> 方法论:分清楚 *功能性需求* 与 *非功能型需求* 之前是想到什么注意什么,往往做不到穷举。 2> 一步一步地重构,其实解决的是自信问题: 做事要先解决思想问题,也就是心理问题: - 没有人能够一步到位地完美解决问题,优秀的代码是演进的,也就是说,代码结构不完美的状态是跳不过去的。 - 我们始终聚焦在解决问题上,代码有问题非常正常。 - 我们要带着成就感不断重构代码,而不是带着对自己否定的愧疚感,这非常重要。 - 成就感让你追求卓越,愧疚感只是让你不想犯错(而这是做不到的)。2020-02-22287
- 辣么大思考题:startRepeatedReport()多次调用,会启动多个线程,每个线程都会执行统计和输出工作。 想了一种简单的实现方式,将runnable做为成员变量,第一次调用startRepeatedReport()时初始化,若多次调用,判空,返回。 public void startRepeatedReport(long periodInSeconds, long durationInSeconds) { if (runnable != null) { System.out.println("duplicate calls!"); return; } runnable = () -> { long durationInMillis = durationInSeconds * 1000; long endTimeInMillis = System.currentTimeMillis(); long startTimeInMillis = endTimeInMillis - durationInMillis; doReport(startTimeInMillis, endTimeInMillis); }; executor.scheduleAtFixedRate(runnable, 0, periodInSeconds, TimeUnit.SECONDS); } 代码放在了:https://github.com/gdhucoder/Algorithms4/tree/master/designpattern/u402020-02-03519
- Andy老师能提供课程代码吗?2020-02-0416
- 平风造雨调用多次可以通过多线程共享的状态变量来解决,CAS或者加锁进行状态的变更。2020-02-0314
- 6点无痛早起学习的和尚这两篇实战对自己的感觉就是越来越懵,可能还需要多读读,也不知道是不是跟自己的项目做的很少有原因,前面的理论都还能消化2020-03-0417
- undefined深入浅出,过瘾。2020-02-037
- Jxin先回答问题: 1.会导致多余线程做多余的统计和展示。因为每次调用都会起一个异步线程输出统计数据到控制台。这样既会带来额外的性能开销,又会导致统计信息不易阅读。 2.在ConsoleReporter内部维护一个可视字段 started。然后在方法执行时,优先判断该字段是否已经变为true。如果是则不再往下执行。也算是保证该函数的幂等性。 个人疑问: 1.怎么做到这样分步展示重构过程的?我现在写,基本一边写就一边重构,停手也就差不多到合适的质量了。刻意要展示重构手法,展示的知识点会有很多疏漏,并无法做到这样一步一步的展示(下意识一步到位,并不知道怎么退到不好的代码结构)。 2.能理解栏主尽量不依赖任何框架的初衷。但对于java,spring其实才是标准,感觉是不是基于spring框架来写demo还好点? 我现在比较喜欢让代码依赖spring框架来实现,感觉这样会显得优雅一些。栏主怎么看?2020-02-0367
- 高源老师39,40课完整源代码可以提供下吗,我准备好好研究学习下2020-02-0337
- Q罗终于进去到期待已久的设计模式了2020-03-184
- javaadu课堂讨论,使用一个标记flag作为该函数被调用国的标记,并给这个函数加锁,解决并发问题2020-02-034
收起评论