设计模式之美
王争
前 Google 工程师,《数据结构与算法之美》专栏作者
123425 人已学习
新⼈⾸单¥98
登录后,你可以任选6讲全文学习
课程目录
已完结/共 113 讲
设计模式与范式:行为型 (18讲)
设计模式之美
15
15
1.0x
00:00/00:00
登录|注册

39 | 运用学过的设计原则和思想完善之前讲的性能计数器项目(上)

课堂讨论
面向对象设计和实现要做的事情
面向对象设计中的最后一步
EmailReporter
ConsoleReporter
Aggregator
EmailReporter
ConsoleReporter
EmailViewer
ConsoleViewer
Aggregator
EmailReporter
ConsoleReporter
Aggregator
RedisMetricsStorage
MetricsStorage
MetricsCollector
重点回顾
Review版本2的设计与实现
针对版本1的问题进行重构
回顾版本1的设计与实现
运用学过的设计原则和思想改进性能计数器项目(上)
参考文章

该思维导图由 AI 生成,仅供参考

第 25 节第 26 节中,我们讲了如何对一个性能计数器框架进行分析、设计与实现,并且实践了之前学过的一些设计原则和设计思想。当时我们提到,小步快跑、逐步迭代是一种非常实用的开发模式。所以,针对这个框架的开发,我们分多个版本来逐步完善。
在第 25、26 节课中,我们实现了框架的第一个版本,它只包含最基本的一些功能,在设计与实现上还有很多不足。所以,接下来,我会针对这些不足,继续迭代开发两个版本:版本 2 和版本 3,分别对应第 39 节和第 40 节的内容。
在版本 2 中,我们会利用之前学过的重构方法,对版本 1 的设计与实现进行重构,解决版本 1 存在的设计问题,让它满足之前学过的设计原则、思想、编程规范。在版本 3 中,我们再对版本 2 进行迭代,并且完善框架的功能和非功能需求,让其满足第 25 节课中罗列的所有需求。
话不多说,让我们正式开始版本 2 的设计与实现吧!

回顾版本 1 的设计与实现

首先,让我们一块回顾一下版本 1 的设计与实现。当然,如果时间充足,你最好能再重新看一下第 25、26 节的内容。在版本 1 中,整个框架的代码被划分为下面这几个类。
MetricsCollector:负责打点采集原始数据,包括记录每次接口请求的响应时间和请求时间戳,并调用 MetricsStorage 提供的接口来存储这些原始数据。
MetricsStorage 和 RedisMetricsStorage:负责原始数据的存储和读取。
Aggregator:是一个工具类,负责各种统计数据的计算,比如响应时间的最大值、最小值、平均值、百分位值、接口访问次数、tps。
ConsoleReporter 和 EmailReporter:相当于一个上帝类(God Class),定时根据给定的时间区间,从数据库中取出数据,借助 Aggregator 类完成统计工作,并将统计结果输出到相应的终端,比如命令行、邮件。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了如何通过重构和设计原则来改进性能计数器项目。作者首先回顾了项目的第一个版本的设计与实现,指出了Aggregator类和ConsoleReporter、EmailReporter类存在的问题。在版本2中,作者计划利用重构方法对版本1的设计与实现进行改进,解决存在的设计问题,让其满足设计原则、思想和编程规范。具体来说,对Aggregator类的重构解决了代码量增加、可读性、可维护性变差的问题;对ConsoleReporter和EmailReporter类的重构解决了代码重复、职责不够单一、可测试性有待提高的问题。通过对这些类的重构,作者逐步完善了框架的功能和非功能需求,使其满足之前罗列的所有需求。整体而言,本文以项目的迭代开发为线索,深入讲解了如何运用设计原则和思想改进性能计数器项目,对于想要提升项目设计与实现水平的开发者具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》
新⼈⾸单¥98
立即购买
登录 后留言

全部留言(46)

  • 最新
  • 精选
  • 辣么大
    问题1,reporter可测性差的问题,可以mock storage,将request信息到map中。 // mock MetricsStorage storage = new MockRedisMetricsStorage(); 问题2,reporter的创建过程可以使用简单工厂方法。Aggregator完全没有必要暴露出来,可以隐藏。 ConsoleReporter consoleReporter = ReporterFactory.createConsoleReporter(storage); 争哥的代码我复制下来,并且跟着重构了一下,想跑跑看的同学请参考: https://github.com/gdhucoder/Algorithms4/tree/master/designpattern/u39
    2020-02-01
    55
  • javaadu
    1. 看了下,ConoleReporter和EmailReporter的核心区别在于使用的显示器不同,另外就是调度的频次不同,第二个不同是可以通用化的,可以提取出一个抽象的调度器(把查询数据、调用聚合统计对象的代码都放进去),支持每秒、分、时、天调度;ConsoleReportor和EmailReporter都使用这个调度器,自己只维护对应的显示器对象的引用就可以了。
    2020-01-31
    26
  • 小晏子
    课后思考: 1. 将两个reporter中的run里的逻辑单独提取出来做成一个公共函数void doReport(duration, endTime, startTime),这个函数易于单独测试,两个reporter类中调用doReport,因为两个reporter类中并无特殊的逻辑处理,只使用了jdk本身提供的功能,我们可以相信jdk本身的正确性,所以这块就可以不写单元测试了,这就简化了测试也解决了重复代码的问题。
    2020-01-31
    19
  • javaadu
    2. 如果使用Spring Boot之类的框架,就可以利用框架做自动注入;如果没有,则可以用工厂方法设计模式来拼比掉复杂的对象创建过程
    2020-01-31
    16
  • 守拙
    课堂讨论 1. 今天我们提到,重构之后的 ConsoleReporter 和 EmailReporter 仍然存在代码重复和可测试性差的问题,你可以思考一下,应该如何解决呢? ConsoleReporter和EmailReporter的代码重复集中在viewer#output()部分.可以抽象一个AbsReporter,将重复代码放在基类中,并让ConsoleReporter和EmailReporter继承自AbsReporter. 这里基类与衍生类完全符合is-a关系, 但并未使用多态性. 2. 从上面的使用示例中,我们可以看出,框架易用性有待提高:ConsoleReporter 和 EmailReporter 的创建过程比较复杂,使用者需要正确地组装各种类才行。对于框架的易用性,你有没有什么办法改善一下呢? ​ 可以使用builder模式改造, 提供更友好的依赖注入方式. 除此以外, 还应编写良好的注释, 帮助客户端程序员正确的使用框架. ​ 示例: ​ ConsoleReporter instance = ConsoleReporter.Builder() ​ .setMetricsStorate(storage) ​ .setAggregator(aggregator) ​ .setStatViewer(viewer) ​ .setExecutor(executor) ​ .build();
    2020-01-31
    14
  • Jessica
    这句话太赞同了:面向对象设计和实现要做的事情,就是把合适的代码放到合适的类中。当我们要实现某个功能的时候,不管如何设计,所需要编写的代码量基本上是一样的,唯一的区别就是如何将这些代码划分到不同的类中。不同的人有不同的划分方法,对应得到的代码结构(比如类与类之间交互等)也不尽相同。
    2020-03-17
    10
  • Jxin
    1.将定时和输出报表这两件事分离。单独的定时线程,在关键的时间点都触发一个事件。输出报表的两个类去监听自己关心的时间job的事件(生产消费模式)。如此一来,定时触发好不好使不再是我api使用方考虑的事。我只需要测试对应输出报表的业务是否正常。然后就控制台和邮件这两个报表类,其生成报表的逻辑是一样的,仅仅是展示的“方式”不一样。所以让我选,我会合并这两个类,生成报表的逻辑为私有方法,然后单独写一个控制台输出的public方法和邮箱输出的public方法(输出模式多,且存在组合需求的话会采用分发+约定的方式,降低调用方负担)。那么这个类,生成报表逻辑公用,两个输出方法是走的api,所以也不关心,我只需要测试 报表生成的逻辑即可。 2.越灵活自然越复杂。 约定大于配置呗。除了业务埋点必须实现,其他都可以约定。
    2020-01-31
    7
  • 时熵
    Aggregator重构后时间复杂度感觉上升了好多
    2021-07-02
    3
    5
  • 红豆成香
    老师,大家好,有个问题一直困扰着我,看到老师这里也存在,希望老师和同学们帮我解惑:max和min等拆分成独立的函数之前,一个for循环就可以同时完成计算;拆分之后,每个独立的方法都要循环一次,如果数据很大,这样就很耗时间,而且我总觉得一个for循环能解决多个问题特别的爽,有一种一石二鸟的感觉,但是拆分之后代码逻辑更加清晰,我不知道要怎么取舍了
    2020-11-10
    5
    5
  • liu_liu
    1. 可定义父类,重复代码抽取为函数进行复用 2. 用工厂方法,屏蔽创建过程
    2020-01-31
    5
收起评论
显示
设置
留言
46
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部