设计模式之美
王争
前Google工程师,《数据结构与算法之美》专栏作者
立即订阅
18516 人已学习
课程目录
已更新 29 讲 / 共 100 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 (1讲)
开篇词 | 一对一的设计与编码集训,让你告别没有成长的烂代码!
免费
设计模式学习导读 (3讲)
01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?
02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?
03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
设计原则与思想:面向对象 (11讲)
04 | 理论一:当谈论面向对象的时候,我们到底在谈论什么?
05 | 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
06 | 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
07 | 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
08 | 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
11 | 实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
12 | 实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
13 | 实战二(上):如何对接口鉴权这样一个功能开发做面向对象分析?
14 | 实战二(下):如何利用面向对象设计和编程开发接口鉴权功能?
设计原则与思想:设计原则 (12讲)
15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?
16 | 理论二:如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
17 | 理论三:里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?
21 | 理论七:重复的代码就一定违背DRY吗?如何提高代码的复用性?
22 | 理论八:如何用迪米特法则(LOD)实现“高内聚、松耦合”?
23 | 实战一(上):针对业务系统的开发,如何做需求分析和设计?
24 | 实战一(下):如何实现一个遵从设计原则的积分兑换系统?
25 | 实战二(上):针对非业务的通用框架开发,如何做需求分析和设计?
26 | 实战二(下):如何实现一个支持各种统计规则的性能计数器?
不定期加餐 (2讲)
加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法
加餐二 | 设计模式、重构、编程规范等相关书籍推荐
设计模式之美
登录|注册

25 | 实战二(上):针对非业务的通用框架开发,如何做需求分析和设计?

王争 2019-12-30
上两节课中,我们讲了如何针对一个业务系统做需求分析、设计和实现,并且通过一个积分兑换系统的开发,实践了之前学过的一些设计原则。接下来的两节课,我们再结合一个支持各种统计规则的性能计数器项目,学习针对一个非业务的通用框架开发,如何来做需求分析、设计和实现,同时学习如何灵活应用各种设计原则。
话不多说,让我们正式开始今天的内容吧!

项目背景

我们希望设计开发一个小的框架,能够获取接口调用的各种统计信息,比如,响应时间的最大值(max)、最小值(min)、平均值(avg)、百分位值(percentile)、接口调用次数(count)、频率(tps) 等,并且支持将统计结果以各种显示格式(比如:JSON 格式、网页格式、自定义显示格式等)输出到各种终端(Console 命令行、HTTP 网页、Email、日志文件、自定义输出终端等),以方便查看。
我们假设这是真实项目中的一个开发需求,如果让你来负责开发这样一个通用的框架,应用到各种业务系统中,支持实时计算、查看数据的统计信息,你会如何设计和实现呢?你可以先自己主动思考一下,然后再来看我的分析思路。

需求分析

性能计数器作为一个跟业务无关的功能,我们完全可以把它开发成一个独立的框架或者类库,集成到很多业务系统中。而作为可被复用的框架,除了功能性需求之外,非功能性需求也非常重要。所以,接下来,我们从这两个方面来做需求分析。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《设计模式之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(38)

  • 辣么大
    没有经历过大型系统的全过程(设计,开发,实现,维护)。自己开发一些功能时,比较喜欢“用户故事”,这样能基本能做到一次交付一个可用功能。干就是了!先有一个原型,然后再迭代优化。最后“纸上得来终觉浅”,照着争哥的代码还是自己实现了一下:https://github.com/gdhucoder/Algorithms4/tree/master/designpattern/u025
    2019-12-30
    2
    10
  • 小畅
    打卡似懂非懂
    2019-12-31
    3
  • Monday
    手机听读终觉浅,归来PC撸代码.。
    GET完。代码:https://gitee.com/MondayLiu/geek-design.git
    2019-12-30
    3
  • progyoung
    老师,本文中的案例统计时间时对业务代码是侵入式的,有没有非侵入式的案例呀?

    作者回复: 可以使用类似spring aop 做到无侵入

    2019-12-30
    1
    3
  • 北天魔狼
    一直没有做过关于统计和监控的项目,希望老师可以出一个小的MVP🙏🙏🙏

    作者回复: 39 40讲 会给出完善的代码

    2019-12-30
    3
    3
  • 荀麒睿
    我觉得技术人需要一些产品的思维,这样即使在做已经设计好的产品的时候,也能提出一些不同的看法和见解,而不是一味的做一个执行者,别人说啥就做啥,而且框架的设计我觉得也是一个产品,需要我们技术人自己去推敲去打磨。
    2019-12-30
    2
  • 桂城老托尼
    感谢争哥分享,先看了第一段过来作答,完了再回到文章验证想法。
    统计接口各维度信息的框架设计思路如下,
    1,确认框架职责,框架的用例。采集原始数据(标准埋点日志),加工原始数据(时间窗口内),提供外围消费(适配各种style)
    2. 细分每一职责,采集原始数据,围绕框架提供能力,确定原始数据标准,甚至原始数据标准的定义也开放给业务系统,解析关键信息的规则由业务系统自己把控。框架负责制定规则的枚举,和规则解析。
    3. 加工原始数据,其实就是使用规则对原始数据流进行解析和统计,这里可以给出默认时间窗口和更新周期,业务系统可配置变更。
    4. 提供外围系统消费,框架给出指标数据,自己默认展示样式,自定义样式留好扩展,交给业务系统自己扩展,框架也可以管控起来,形成类似于“主题市场”的东西。
    总结下来,就是确定职责边界,高内聚框架职责,低耦合业务系统,对修改关闭,对扩展开放。基于这些原则,再往上走就是各种xx设计模式了,这时候就是水到渠成的事儿了。
    -----回去再看下文章验证下猜想,不被打脸才好 。
    2019-12-30
    2
  • 像这种统计频次的功能,是通过集成框架去实现好,还是说通过mq由消费服务去实现好
    2019-12-30
    1
    2
  • Flynn
    老师,后面有TDD相关的内容讲解和练习么

    作者回复: 有单元测试的讲解

    2019-12-30
    2
  • 再见孙悟空
    使用线框图,采用最小原型模式,先做出一个模型,画出模型图,然后再迭代优化,使抽象的东西变得看得见摸得着,这确实是一个好方法,实际项目中也不知不觉用到了这种思想,做非业务类的需求如此,业务类的也一样。还有留言里说的用户故事也是很不错的方法,通俗点就是技术要有产品的思维,站在使用者的角度看问题。
    2019-12-30
    1
  • javaadu
    还没有看文章的方案,先来留个言:
    运行时:框架的接口是注解;通过mq将统计的数据发出到实时计算引擎例如flink,编写udf统计各种特征数据

    管理时:核心是数据存储和查询模块;渠道接入放在独立的模块
    2019-12-30
    1
  • 朱晋君
    1.对于大型复杂的系统,可以先进行功能模块拆分,确定好业务边界,部署方式,模块间通信,对单个模块使用文章中的绘图方法来实现。
    2.我觉得程序员必须具备产品思维。假如我们做的直接面向用户的系统,思考用户使用情况会对我们的设计实现有很好的指导作用。假如我们做的是提供给上游系统的服务,要考虑上游系统的情况,比如调用链,服务修改对上游造成的工作量,调用频次,故障影响等。
    2020-01-01
  • xavier
    对于复杂系统,先按照功能模块划分,然后各个击破。
    2019-12-31
  • Geek_342489
    之前看我们中心同事开发的一些监控、鉴权相关的中间件代码感觉很牛,但具体哪里牛说不上来,听了争哥的课,做到知其所以然,感觉距离自己写出让别人“感觉很牛”的代码更近了一步,感谢!
    2019-12-31
  • 无刀
    解答了我好多的疑惑,每天都盼着有更新
    2019-12-31
  • Geek_Zjy
    本节理解:
    1. 功能列表,往往对应方法签名列表,主要分为采集功能、聚合计算功能、持久化功能
    2.聚合计算(功能列表的一部分)的功能往往在持久化的基础之上
    3.存储部分是采集部分的结果,又常常是聚合功能的输入
      当然如果使用了其他同学留言说的流计算,可能这个存储相当程度上指缓存
    4.最小原型部分当然是个好办法,我个人唯一可以补充的是,老师和大家肯定也这么做了,但是未提到的是:做最小原型时,可以记下很多的 TODO 和疑问,然后通过反复迭代修复补充改进
    5.我个人还有一种感觉,就是每一个层面都会有核心部分,核心部分往往是稳定的,
      还有一些啮合部分,啮合部分往往是可扩展的,比如Spring 的视图解析,数据源适配,
      当然SpringBoot 也提供了StopWatch这样的功能和老师现在做的功能有部分雷同,可以对比参考,可能会对理解整个功能有很好的帮助
    2019-12-31
  • Chen
    肯定要有产品思维啊,不然怎么跟产品扯皮
    2019-12-31
  • 刘大明
    没有经历过特别复杂的系统。一般工作中遇到需求,第一步是做业务分解和用户故事。将一个功能分解成一个个小任务,理清楚每个小任务之间的关联关系。任务分解清晰之后可以用tdd的方式实现一个最小原型版本,然后在这个最小原型的版本上面持续重构。
    问题2我觉得技术肯定还是要懂产品的,毕竟产品才是公司最需要的东西,有产品能力的技术才能在很多编码和设计的时候让产品更容易扩展。
    2019-12-30
  • DullBird
    问题1:
    1.1一般会画一下用例图,标注一下优先级,然后针对核心用例,简化它,不要考虑太多个性化的东西。先实现最通用简单的一个场景。
    1.2 流程很复杂的时候,会画流程图,泳道流程图,一方面可以很清楚查漏补缺,另一方面泳道就划分了模块。
    问题2: 其实上面1.1,就需要程序员有产品的思维,要知道什么是业务最核心的需求,哪些个性化其实只是为了满足这个核心需求的点缀。程序员不能只关注技术,否则可能花了很多时间。但是解决了一个并不是业务痛点的情况。
    2019-12-30
  • whistleman
    最小原型是很棒的方法,跨出第一步就成功了一半
    2019-12-30
收起评论
38
返回
顶部