《软件方法(下)》8.3.2.2 警惕拼凑泛化(202405更新)

DDD领域驱动设计批评文集

做强化自测题获得“软件方法建模师”称号

《软件方法》各章合集


8.3 建模步骤C-2 识别类的关系

8.3.2 识别泛化关系

8.3.2.1 识别泛化的思路

(3)自上而下(从一般到特殊)

如图8-92所示,这个识别思路就是8.2.5.6 属性是否对所有对象都有意义里的思路。

图片

图8-92 自上而下-一个类分裂出子类

和上面的“自下而上”一样,这里的属性也包括关联,如图8-93。

图片

图8-93 关联只对部分对象有意义时分出子类

不一定像图8-93那样关联到不同的类。关联到同一个类但角色名不同,而某个角色只对部分对象有意义,也可以考虑分出子类,如图8-94。

图8-94 某个角色只对部分对象有意义时分出子类

8.3.2.2 警惕拼凑泛化

您可能注意到,以上我们尽量通过属性(包括关联)来解释泛化关系。

虽然泛化带来的好处是落在行为上,但如果抛开属性直扑行为,很可能会带来“伪泛化”、“伪面向对象”。

如图8-95,因为X和Y都有操作op1,所以泛化出A,把op1提上去成为抽象操作。这个没有问题。

问题出在前面,怎么知道op1作为X和Y的操作是合适的?最终的依据还是X和Y的属性(包括关联)。

图8-95 操作怎么来的,需要有依据

有一种偷懒遮羞布,就是胡乱安排操作,然后拼凑出泛化关系,根本不顾安排的操作是否合理。

一些伪面向对象实践经常得到各种名称的最后是or或er(汉语则为“器”)的类。

开发人员可能一开始按照面向过程的思路噼里啪啦把代码写出来,然后出于赶时髦需要“面向对象”,他就把过程名称加上or或er作为类名称,然后把原来的过程作为or或er类的操作。

当存在多个类似过程时,还可以加上一些泛化关系(或接口-实现)来做点缀,如图8-96,这样看起来就更有“面向对象”的味道了。

图片

图8-96 带有泛化关系的or或er类

可能在某些开发人员眼里,图8-96很有格调,可以用来吹嘘的高大上词汇有:OCP(开放-关闭原则)、DIP(依赖倒置原则)、模板方法模式……等。这些由泛化关系衍生出来,被网红圈子广泛吹嘘的原则和模式作用十分有限,指望了解被包装出来的“SOLID原则”之类就能应对软件复杂性,那真是太天真了。

★关于Robert C. Martin和他的书《敏捷软件开发-原则、方法与实践》的评价,参见本书2024版第1章关于“敏捷”染色的阐述

or或er类往往没有属性,只有操作,大量的逻辑仍然隐藏在子类操作的实现中。当然,开发人员也可能觉得这是好事,“这说明我有算法啊!”,好像很高大上,但这所谓的“算法”(其实是核心域逻辑)正是建模的重点,结果被开发人员完美地遮掩过去了。

和其他的偷懒遮羞布类似,这种or或er的做法一一对应,思考工作量小,还有各种高大上词汇护法,于是开发人员洋洋得意,感觉自己已经很厉害了,连称“受用”,纷纷去拥抱这种偷懒遮羞布。

or或er类有时会使用“策略模式”作为伪装,如图8-97,哇,我可以灵活组装各种策略!顺便再吹一通“组合优于继承”之类,其实还是换汤不换药,核心域逻辑仍然隐藏在子类操作的实现中。那些“策略”才是建模的重点,同样被开发人员完美地遮掩过去了。

图片

图8-97 “策略模式”换汤不换药

如果一个类的命名中有类似这些内容:er、or、器、策略、Strategy、Policy、规则、Rule、算法、Algorithm……然后这个类或其子类的操作中有长长的“算法”,那么应该思考一下,长长的“算法”中到底定义了哪些变量?哪个部分的代码最复杂?

背后往往就是候选的实体类以及需要封装的操作,尽量分离出实体类,把各种逻辑尽量封装在实体类的操作中。这样的思考更辛苦,但也更有价值。

有心的读者可以仔细观察一下你接触到的领域驱动设计相关的文章,看看有没有这样的现象:

全篇文章没有剖析复杂一点的逻辑,但会有“**策略”、“**规则”这样的类或者组件存在。莫非这些“**策略”、“**规则”是别人已经做好的,他拿来就用?追问下去,多半不是,而是他要负责解决的问题。

你猜我怎么知道是这样?因为我接触的开发团队和开发人员太多了,追问下去,脓包破裂的概率极高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值