软件方法(下)第8章分析之分析类图—知识篇Part09-审查类和属性1

可到此处下载《软件方法》(下)目前公开的最新pdf版本:

http://www.umlchina.com/book/softmeth2.pdf

8.2.5 审查类和属性

8.2.5.1 属性是否直接描述类

类和属性连在一起说"类的属性",应该能直接说得通,否则类和属性的搭配是不合适的。这个时候应该找到或建立合适的类,把该属性移进去。“属性要直接描述类”这个要求和关系数据库的第三范式“任何非主属性不依赖于其它非主属性”相似。

例如图8-71,“人员的组织名称”中间隔了个“组织”,"类的属性"不能直接说得通,需要添加一个“组织”类,把“名称”挪过去。

图8-71 属性要能直接描述类

如果确定两个类A和B的关联多重性是1对1,而且其中一个类B只有一个属性,那么,可以把B合并进A,如图8-72。

图8-72 特定条件下合并类

图8-71提到的“人员”和“组织”并不符合合并的条件,因为一个组织可以有很多人员就职。符合合并条件的例子如图8-73的“人”和“出生”。一个人只会出生一次,而且出生只关注一个属性:日期,那就可以把“出生”删掉,在“人”中放置“生日”属性。

图8-73 特定条件下合并类示例

“一个人只会出生一次”这一点很稳定,但“出生只关注一个属性”就没那么稳定。如果“出生”需要关注多个属性,那就不宜合并了。

要特别说明的是,习惯于关系数据库建模的建模人员有时会犯这样的错误,在一个类里放上另外一个类的属性作为“外键”。比如针对上面的例子,建模人员会想:“人员”里放“组织名称”确实不合适,但是放个“组织编码”作为外键总可以吧?其实也不可以。"组织编码"是“组织”的属性,是封装在“组织”中的秘密,“人员”不应该拥有“组织”的任何属性,它只能通过关联拥有“组织”对象,然后通过访问“组织”对象公开的操作来间接访问“组织”的属性。

图8-74 不需要“编码”作为“外键”

“人员”里放“组织编码”不合适,放一个无意义的标识“组织ID”呢?同样也不可以。因为这个“组织ID”是“组织”的标识,前文已经说了,标识属性此时不需要存在,所以“组织ID”在“组织”里不存在,更不要说放到其他类中作为“外键”了。

图8-75 不需要“ID”作为“外键”

在设计工作流,需要把类图映射到关系数据库时,确实需要把"组织"表的主键(可能是"编码"也可能是生成的代理主键)放在"人员"表中作为外键,但正如上文所说,这同样是另一个领域的知识,而且映射规律和核心域知识无关。

缺少抽象能力的建模人员,经常会直接把手上素材的信息,一一对应地映射为类和属性,导致本来属于多个类的信息被合并在一个类中,这是违反本小节要点的一个主要来源。

例如,建模人员对照着一张货物运输托运单,直接把它映射成类,照抄上面的每一栏作为属性,如图8-76。

图8-76 错误:直接把素材照搬成类

建模人员有时还觉得挺符合“类的属性”的。“货物运输托运单的货物名称”,没错啊,手边这张货物运输托运单上确实明晃晃地印有“货物名称”四个字嘛。

托运单、出库单、销售单等各种单据,以及身份证、工作证、图书卡、设备卡等各种卡片和证件,在信息时代之前就已经存在了。它们相当于某种存储结构,存储一个或多个概念的信息,只不过保存的载体不是电子载体,而是甲骨、铜器、竹片、木片、帛布、纸张。

现在,既然用信息系统取代了这些单据、卡片和证件,那么要建模的实体类应该是它们所代表的概念,而不是单据、卡片和证件本身。

也就是说,图8-76的“货物运输托运单的货物名称”应该是“货物运输托运单所记录的货物的名称”。

属性如果放在了错误的类,极有可能会导致大量不同对象的某些属性值相同,而这也可以反过来思考,当发现大量不同对象有相同属性值时,可以检查一下,是否有属性放在了错误的类。

就以图8-71为例,如果按照左侧,可能会有如图8-77的一些对象,发现其中“人员”对象345677和345679的“组织名称”相同,可以检查一下,是否可能漏了一个“组织”类。

图8-77 一些人员对象

注意,以上是说“可以检查一下”,不一定就需要调整。多个对象的部分属性值相同的情况很常见,好多人姓名叫“张伟”,好多人年龄是18岁,并不一定要分出来另一个类。

“状态属性”

前文说到词性时,提到了“状态属性”。“状态属性”的名称是一个形容词,类型为布尔类型,用来标记对象是否处在某个状态,如图8-78。

图8-78 状态属性

这些“状态属性”可能是来自素材中的定语,例如,用例规约提到“可享受优惠的顾客”,那么在识别的时候可能会先把“可享受优惠”放在“顾客”类中。

和“类的属性”刚好相反,“状态属性”和类连在一起说,要能说得通"属性的类"。例如,图8-78中,“可享受优惠的顾客”是说得通的。

不过,说得通"属性的类",也并不表明“状态属性”是最终的建模结果。后面的审查步骤中,我们会再审查“状态属性”。

8.2.5.2 属性是否可以从其他地方推导

如果一个属性可以从其他地方推导出来,那么这个属性就是冗余的,可以删掉。

如图8-79,人的年龄可以从出生日期计算得到,应该把年龄删掉。

图8-79 年龄可以从出生日期推导

这个“其他地方”也可以是所关联的类的属性。如图8-80,订单的总金额可以由各个订单项的金额合计得到,那么可以考虑把总金额删掉。

图8-80 总金额可以从各订单项金额合计

“状态属性”

“状态属性”是冗余的,背后往往隐藏着更多的逻辑,需要进一步推导。

例如,图8-77中,“顾客”有一个“状态属性”叫“可享受优惠”,我们可以问:为什么一名顾客可享受优惠,理由是什么?可能是年龄≥70岁,可能是他有个消费账户余额≥5000元,那么应该把这些规则通过类图、状态机图显式建模出来,然后把“状态属性”去掉。

例如,可以画状态机图如图8-81。

图8-81 顾客的状态机片段

也不要用给“顾客”加一个名叫“状态”的属性,如图8-82。

图8-82 不需要名为“状态”的属性

状态机如何实现,是另外一个领域的问题。和标识一样,对象有状态,这是面向对象这个领域的共识,和“顾客”没有特定关系。如果加上去,又变成了废话刷工作量。

很多建模人员自作聪明地给类加一个名叫“状态”的属性,还洋洋得意,“哇塞,我知道这个类有状态噢,我真厉害!”。

关于状态机的建模以及实现,后面章节再详细描述。

*********

清除冗余时,也经常会有人以“性能”作为遮羞布拒绝思考和废话刷工作量。

如果提出性能问题的这个人知道如何在不考虑性能的情况下得到一个清晰、无冗余的模型,那么他还有资格说一说性能问题。

不过,如果他知道如何得到一个清晰、无冗余的模型,说明他具备了一定的建模能力,往往也不会在分析的时候担心性能问题,因为他知道,如果碰到性能问题,可以按照某些套路添加冗余,这些套路和目前所思考的领域知识没有关系,没有必要混杂进来。

在分析工作流不断提出性能问题的人,您可以尝试让他整理一下核心域逻辑,也可以去看看他之前写的代码,大概率会发现其中逻辑的组织是很糟糕的。

/*

这是人的本性中急于回到自己的舒适区的一种表现,不只是在分析工作流如此,其他工作流也会有类似现象。

例如,开发人员没有掌握需求技能,也不愿意学习,即使给他时间去做需求,他也不知道应该怎么做。只好随便找人问问,开个会,走走过场,然后就着急回到编码的舒适区,甚至在讨论需求的时候都已经在不由自主地思考实现小细节。

为什么“现场客户”之类的东西会吸引开发人员,就是迎合人的这些本性,让开发人员可以安然坐在电脑前面,呆在自己的舒适区里。

呆在舒适区并不一定是错的。

如果出于个人爱好和天赋,专精某方面的技能,在某个领域深入挖掘,解决该领域各种难题,这是非常好的选择。不注意自己的爱好和天赋,什么都想学习,很可能什么都浅尝即止,以“学习新知识”来逃避碰到的各种难题。

错的是自欺欺人。

当形势需要人走出舒适区来应对困难的时候,如果说“我只擅长我手上的东西,这个我对付不了,我也没有兴趣和勇气去对付,还是让我解决我擅长的问题吧”,这个可以理解;如果说“这个只需要用我擅长的东西对付就足够了”,那就属于自欺欺人了。

*/
微信:umlchina2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值