Eric Evans的《领域驱动设计》一书,主要讨论的是如何做好OOD(Object-Oriented Design, 面向对象设计),但在面向对象的软件开发过程中,OOD需要基于之前的OOA(Object-Oriented Analysis, 面向对象分析)所产生的分析模型进行设计,而OOA又需要基于之前的需求工作流所产生的用例模型进行分析。这些内容Evans在书中没有讲。所以如果仅读《领域驱动设计》,而没有掌握OOAD整套的方法,是无法将DDD落地的,也无法运用好OOP(Object-Oriented Programming, 面向对象编程)。当需要从一个单体系统中剥离一块业务设计微服务时,不会对这块业务进行软件建模,又何谈运用好DDD呢?从我最近10年接触到的企业内部应用系统的开发人员来看,绝大部分开发人员都缺乏OOADP的实践技能。他们基本上是基于数据库来开发,写出的代码是脚本式的,缺乏面向对象的封装和多态,导致代码难以阅读、扩展和维护。
为了帮助这些开发人员掌握OOADP实践技能,本文以一个大家熟知的"微信朋友圈权限系统"业务为例,参照UP(Unified Process,统一过程)的需求、分析和设计工作流,从业务愿景开始,经历业务用例、责任风暴、分析类图、设计类图,直至样例代码和自动化测试。经历了这些过程,希望能帮助开发人员掌握OOADP的技能,并为实践DDD打好基础。
目录
使用面向对象的分析、设计和编程(OOADP)方法,为微信朋友圈权限(设置->朋友权限->朋友圈)中的“不让他(她)看”和“不看他(她)”两个业务用例进行软件建模,设计出包括属性和方法的分析类和设计类及其之间的关系,并编写样例代码和自动化测试代码,能够实现如下场景:
业务愿景
注意:本操练题目所涉及业务并没有所依赖的外部系统,所以上图右侧并没有辅助业务参与者。
创造"责任风暴"的灵感,来自"事件风暴"(参见我之前有关事件风暴的2个博客:https://cloud.tencent.com/developer/article/1190088, https://cloud.tencent.com/developer/article/1190083)。但前者专注在面向对象责任的识别与划分。通过实践,我认为责任风暴适合开发团队与领域专家共创用例模型,可以作为绘制系统用例图的前奏,甚至可以替代系统用例图。图中每个"责任",可以看作是一个系统用例。
开发人员可以根据微信设置->朋友权限->朋友圈中的“不让他(她)看”和“不看他(她)”的界面,在工作坊中用便利贴共创责任风暴图。
责任风暴图的制作过程,按梳理顺序要点如下:
Service
):识别完责任后,根据业务相关性,可以把"责任"用"服务"来归类,如4个"不让Ta看"的责任,可以归由一个"不让Ta看"的服务来履行有关名词的注意事项:
Moment
的实例数量),那么可以将其划为分析类;反之,若实例数量总是保持恒定(如每个"朋友圈更新"的内容的实例数量只有一个),那么可以将其划为分析类的属性注意责任风暴图中的"责任"都用"Rn"编了号,这是为了方便在"业务规则"的跳转描述中指定要跳转到的"责任"。图中缺"R6"和"R11"的原因,是因为这两个责任在后来发现可以合并到R3和R8,所以就缺了这两个编号。由此可见,OOAD的过程充满了随着渐进明细而不断修正前面工作的特点。
Moment
(朋友圈更新),而每个Moment
只能属于一个User
,所以从User
到Moment
是"一对多"的关系。为了便于分页显示Moment
,且当"多"一方数量很大时无须在User
类里持有一个很大的Moment
的列表,所以图中的箭头只是从Moment
指向User
,表明Moment
会持有一个User
,但User
不必持有多个Moment
AddingFriend
分析类(即上图中的Friend
类,原因见下文),有两个关联的箭头指向User
,表明在AddingFriend
类中,会持有两个User
,一个是me
,表示微信好友,另一个是me
的好友friend
AddingFriend
类,原来叫Friend
类,但后来感觉还是叫AddingFriend
更能反映微信加好友的业务,所以更名。MomentReadPermission
类原来是指向User
类的,但后来发现朋友圈更新阅读权限其实是与所添加的好友相关的,所以改为指向AddingFriend
类。上图中的Friend
类名故意没有更改,出现了与下面设计类图AddingFriend
类不一致的情况,就是要提醒大家注意这一点。但在实际工作中,还是需要改过来,保持一致Role
类表示角色,在本操练中,这个类有两个实例,即"不让Ta看"和"不看Ta"是两个不同的角色MomentReadPermission
类来实现两个"一对多"Service
中实现,如上图所示Service
类,如上图MomentReadPermissionNotAllowedToReadService
类及其4个方法所示Moment
类中添加了contents
属性代码的package组织形式,参考了Tom Hombergs所著的Get Your Hands Dirty on Clean Architecture (https://learning.oreilly.com/library/view/get-your-hands/9781839211966/)第2章所给的六边形架构的图示,如下图所示。
因为已经达成了演示OOADP的目的,所以代码仅实现了以下两个责任(用例):