《软件方法》最近在第8章做了一些调整:
*插入两个小节:8.2.3.3 没有需求规约时的思考、8.2.3.4 长得像用例图的类图
*把"识别关联"提前到"识别泛化"之前
8.2.3.3 没有需求规约时的思考
有可能你是"敏捷"地做需求,只有一个用例图,甚至连用例图都没有,只是说要做什么功能------当然,做这个功能的理由也是"敏捷"的。
即使是这样的情况,前面所说的思考"系统需要懂得哪些概念以及概念之间的关系,才能根据执行者的请求提供恰当的价值"依然有用,但需要建模人员有更强的抽象能力。
日常工作和生活中,可以有意识训练这方面的能力。针对任何一个系统,我们都可以思考:它需要输入什么,能输出什么,为了能把输入变成输出,系统需要懂得哪些概念以及概念之间的关系?
图8-32 思考系统需要封装的抽象
例如,针对日常生活中的网约车系统,我们使用时,第一个交互可能是这样的:
输入:上车地址和目的地址
输出:各个车辆类型的预估费用。
为了能把输入变成输出,系统需要懂得哪些概念以及概念之间的关系?
要能输出预估费用,需要知道车辆类型的公里价格还有订单要走的路程长度。路程长度需要通过上车地址和目的地址来计算,这个计算又涉及到很多和网约车并非特定相关的复杂概念,由专门的组件来完成是更合适的。思考结果如图8-33。
图8-33 网约车系统思考结果
读者可以自行做类似思考,例如,以取款机为研究对象:
(1)如果输入为:账号、密码、取款金额,要提供取现金的价值,系统需要懂得哪些概念及关系?
(2)如果进一步减少输入,改为输入:账号、密码, 系统需要懂得哪些概念及关系?
(3)如果把输入改为刷脸, 系统需要懂得哪些概念及关系?
**********
如果没有这样的抽象能力,很容易出现"类图长得像用例图"的现象。
例如,一个电商系统,开发人员一开始心里有一个想法,要做一个"搜索商品"的功能。那么要实现这个功能,需要什么类呢?开发人员干脆就按看到的表面现象来找类,得到的类图长得非常像用例图,如图8-34。
图8-34 长得像用例图的类图
但是,系统之所以能够为顾客查询"屏幕尺寸为6英寸的Android手机",不是因为它记住了"哪位顾客查询过什么商品",而是因为它记住了各种商品的类别和特征。我们需要的、更合适的类图应该类似于图8-35。
图8-35 更合适的类图
Martin Fowler的"Refactoring: Improving the Design of Existing Code"第1版中,第1章举了一个影片店系统的例子,从一开始的不合理结构代码,然后不断重构,得到更合理的结构。一开始的类图如图8-36所示。
图8-36 "Refactoring: Improving the Design of Existing Code"中一开始的类图
(没有途径获得清晰的Refactoring原书截图,上图是我按照原书内容绘制,并加了中文注解。)
图8-36的类图长得很像影片店系统的用例图,画出来像图8-37:
图8-37 影片店系统的用例图(根据Refactoring书中内容绘制,原书无此图。)
如果拥有上面所说的思考能力,看到长得像用例图的类图心里就会响起警铃。影片店系统要提供"租借影片"的价值,系统需要懂得的关键信息很可能并非哪位顾客租借了哪部影片,即图8-36中的三个类,而是其他的信息,如影片的价格体系和库存、顾客的等级。
有了这个警铃,就不用多此一举,先假装弱智写出弱智代码,再"重构"成稍微聪明的样子------这里的强行降智和第1章所提到的伪创新"割裂历史"类似。
8.2.3.4 长得像用例图的类图
系统的需求可以看作解决组织问题的解决方案,而系统的类可以看作解决系统需求的解决方案。如果一个解决方案不需要什么思考就可以得到,要么这个解决方案是错的,要么要解决的问题价值已经很小。
长得像用例图的类图,需要的思考非常少,这样的类图很可能带来的价值是非常小的。要么类图错了,要么系统的需求已经没有多少价值。
上文说到,图8-34的用例"顾客→查询商品"对应的合适类图是图8-35。
我们可以进一步思考,如果"哪位顾客在什么时间查询了什么商品"成为系统需要记住的关键信息,那么图8-38的类图是合适的:
图8-38 "哪位顾客在什么时间查询了什么商品"成为系统需要记住的关键信息
此时,系统的用例很可能并非图8-34中的"顾客→查询商品",而是类似于图8-39:
图8-39 图8-38对应的合适用例图