建议用 Firefox 85+、Safari 14+、Edge 87+ 浏览
我的文章 我的评论 我的书评 我的知乎*
书单 书讯 书评
需求知识体系 特性 用例 统一用例方法 用户故事 需求工具
业务建模 UML OOD
敏捷知识体系 敏捷方法 敏捷问答 敏捷工具 敏捷评论 敏捷资源
业务模式 需求模式 架构模式 设计模式 大道至简:实话设计模式 Web 应用架构模式
.NET Java JS 笔记
Amazon* ITPub* Martin Fowler* 教程
需求分析需求模型非功能需求业务需求分析
SpringJSF
> 建模 > UML > > 建模 > UML >
在线/227 登录/0

UML 中文 FAQ

阅读数:48.1K
基本历史

问:张老师,请教你一个关于设计类导航方向的问题。在使用 UML 做设计类图的时候,我常常会遇到这样的困惑:该如何决定类关联导航的方向,比如:Customer 与 Order 之间的关联。因为关联导航的方向通常决定了一个类是否该持有另一个类的引用。(网友 GouGou,2007-6-27)
class Customer
{
private List<Order> _orders;
...
}

class Order
{
private Customer _cus;
  
public Order(Customer cus);
...
}
但这常常很难说清楚。我常常试着从 UML 序列图来加以判断,从对象的动态协作分析,只有到某个类确实需要引用到另一个类的时候才会把这样的引用加上去。但是有的时候好像也说不太清楚,感觉是一件很钻牛角尖的问题。

比如上面的例子,似乎 Customer 不需要了解 Order,但是像操作 AddOrder(Order), DeleteOrder(OrderID) 交给谁好呢?而 Order 需要引用到 Customer 的原因是,比如在打印 Order 的时候,如 Print(Order o),Order 对象显然应该知道它所属的 Customer 是谁。

是不是我的理解有所偏差呢,请张老师指点一下,或者有这方面的资料、书籍可否推荐,谢谢。



答: GouGou,你好!决定设计类关联关系的导航方向,是单向关联,双向关联,还是没有关联,其实这些都是可选方案,确定采用哪种关联以及关联的方向,完全取决于你对软件的设计,也就是说,这些都是人为的。当然,对于最终设计结果,我们还是有一个判断准则:比如,结果设计类图是否做到了高内聚、低耦合,是否能够实现方便的类访问,执行效率如何、扩展性如何等等。

从你给的以上例子 Customer-Order 代码看,你在这两个类之间建立了一种紧密的聚合关系(Aggregation):Customer 聚合了多个 Order 对象(一对多),而每个 Order 对象又与一个 Customer 对象关联(一对一)。这当然是一种可行的设计方案。这种双向关联关系(聚合是一种强关联)的好处是访问比较方便,从两个导航方向都可以轻松获得所需要的信息/数据。缺点是什么?构造/建立这样一种双向关联关系比较麻烦一点,至少需要两次对象初始化,以保存对关联对象的引用。而且,两个设计类之间直接建立这种双向关联,就形成了紧耦合,对其中一个类的改变会影响到另一端的类对它的引用。

单纯从这两个类看,采用单向还是双向关联,好像都是对的,只要能够实现软件功能而且访问对象方便,本无所谓。要最终判断这个设计好不好,我建议把考察边界扩大一点,也就是考虑你的软件中 Customer-Order 周边的对象,看看其他对象是如何使用它们的,比如,在用例(use case)功能的实现路径上考察这两个对象的导航关系,这样我们就能更全面地作出判断。

你根据序列图(sequence diagram)来判断是否需要某个方向的关联,这也是一种正确的做法。问题是,有的时候,我们不会在设计时把所有的序列图都完整地画出来,这时候就需要运用、结合其他方法来判断了。

关于 Customer-Order 之间应该建立双向关联,你给出的两条理由也是对的,这当然也是一种可行的判断依据。既然有充分的理由,就可以建立双向关联。

事实上,两个类之间有没有、该不该建立关联关系这件事情本身,比这个关联的导航方向,是单向,还是双向,更为重要。前者为主,后者为次。即使导航方向错了,也没关系,毕竟你还可以轻松重构么。因此在实践中,尤其在敏捷建模和架构设计的时候,我们往往只在两个类之间画上表示关联的连线就足够了,而不必过分关注导航箭头的方向,这是一个不太重要的细节。当然,如果你有充足的理由可以肯定正确的导航方向,也可以在设计类图中直接标明;如果不能马上确定,我建议推迟决策,先假定双向都可以访问,然后等到编码时或者掌握足够判断依据时再明确指定和重构。

另外还有一种判断方法,是从 OOA(面向对象分析)层面考虑。作为分析类(不同于你所说的设计类),Customer-Order 类之间是否应该建立关联完全取决于业务的需要。很多时候分析模型对于你的 OOD 和程序设计可以起到借鉴参考作用。比如,如果业务要求,从每张订单 Order 中,都可以知道该订单来自于哪位客户 Customer,那么在分析模型中 Order 必然有一个关联指向 Customer。另一方面,是否每个 Customer 都能知道他下了哪些订单呢?我们不知道,这要看具体业务和应用环境的需要。

OOA、OOD 会影响我们的面向对象程序代码,而 OOD 包括设计类图的导航关系可以参考 OOA 分析的结果。这样,就不会出现类似“Customer 不需要了解 Order”这样模棱两可的问题了。“Order 对象应该知道它所属的 Customer 是谁”,你的这一结论其实正是来自于业务分析,也就是在实际的订单上有客户的名称,这样你在打印的时候自然需要知道而且标明客户是谁了。

我们的设计其实最终都来源于需求,服务于需求。如果设计类 Customer-Order 之间不建立任何关联,也能满足需求和用例功能实现的需要(请考虑这种情况是否有可能存在?),那么这就是最优的、最简单的设计。我的意思是说,事实上不存在绝对完美(100% perfect)的设计,OOD 要因时因地,也就是根据具体的 Application Context 而定。一种好的设计换一个应用环境,可能就变成了差的设计。这就是我的太极 OO 思想的一种观点。

小结一下:

关于两个设计类之间的导航方向问题,这并不是一个牛角尖问题,可以有很明确的答案。当然,这需要你要根据一定的设计原则和应用环境来思考,作出决策,以能否使结果程序代码更简洁、更高效、更灵活等质量要素为最终判断依据。掌握 OOD 的基本原则(比如高内聚、低耦合等等),以不变应万变,这才是 OO 设计的关键所在。

不知道你对 OOA、OOD 的概念和设计原则是否很熟悉,建议你仔细看一下《UML 用户指南》或者 Larman 的《UML 和模式应用》,里面有较详细的关于关联关系、OOD 设计原则的探讨。感谢你的提问!

<帮助> <全部评论> 共 1 个主题 2 条评论 (umlfaq)
(1) 回复-可否推荐一些实用的 UML 学习资料
(张恂 99 字 0 回复 E2007-1-18 10:16:39 LID:2)
(2) [转] 可否推荐一些实用的 UML 学习资料
(张恂 159 字 1 回复 E2007-1-18 10:15:33 LID:1)
首页 | 使用指南 | 站点地图 | 版权声明 | 联系方法 | © 2005-2022 张恂 版权所有. 沪ICP备15017521号-2