下一种,这个类和类之间的关系就是聚合关系,聚合关系呢, 在
UML中呢,实际上是一种特殊的关联关系,它表示一种语意上的一种整体与部分的关系。
所以呢,这个本身这个聚合关系呢, 这个不同的这个专家争议非常大,在
UML中这个 不但定义了这个聚合关系,而且定义了一种特殊的聚合关系,称之为组合关系。
所以这就使得很多的专家对这个问题呢,有了一些 这个不同的看法。
那么 我们呢,首先看一下这个聚合关系
是什么意思,它是一种特殊的关联关系。
除了描述这个整体和这个两个类之间的关联关系之外,还描述这个两类
是一种这个不对等的,也就是说一个是整体一个部分,它们之间的整体与部分的关系。
那么到底什么是整体、 部分关系,如何来定义整体、 部分关系。
这实际上是一个 非常深入的一个话题,也就是我们在定义
我们在这个识别整体、 部分关系时候,我们实际上很多情况下是不假思索的。
通过感觉就可以,这个认, 觉得,感觉觉得这俩是整体与部分关系,比如说人的
这个四肢躯干,然后和人作为一个整体与部分关系, 是吧?汽车的轮子、 发动机和整个汽车是个整体部分关系。
但是你问它为什么它们之间,为什么是一个整体与部分关系,而不是一个一般的关联关系呢?
这很多人往往说不清楚,这个问题,也就是这个东西呢,很大 程度上是取决于我们这种自然这种思维方式,
是一种本能的直觉,一种感觉 但是呢,很多研究者呢就是想这个
给出一种这个,这种存在背后的 一种的存在,也就是说要真正深入研究到底为什么?
我们会把某些关系划定为整体与部分关系 ,而某些关系不是整体与部分关系。
想搞几个判定的一些准则,这个
这个是也是这个,当然已经是超出了软件本身的
这个研究范围,研究这个问题呢,涉及到哲学、 心理学、 社会学
等等一些问题,另外一个研究呢,就是研究这个整体部分关系的分类问题。
这个到底从这个 一般意义上来看,这种关系到底分几类。
但是UML这里边给它分为两类显然是不够完备的。
这是UML的一个问题。
UML是怎么分类的呢?UML认为 它是把这个关联关系分为一般一种聚合关系与组合关系。
那么什么是组合关系呢?它认为是一种非常强的 组合关系,也就是说什么呢,整体和部分之间
生命周期是一致的,也就是整体,部分随着整体的产生而产生, 随着部分的消亡而消亡,正是因为它们生命周期是一致的,
在这个生命周期的时候,这个部分不可能既属于
整体1又属于整体2,因为一旦这个整体1消失之后呢 这个这个部分呢,实际上这个
是就会发生矛盾,是吧?这个 它如果是整体1的一部分,那么它应该是跟着消失,
它如果整体2的一部分,整体2还没消失,它应该,它应该是跟着它。
所以,从这个角度来看呢,这个
正是由于它们生命周期,它们整体和部分之间生命周期是 完全一致的,所以这个部分这端的
这个,这个整体这端的多重性啊,不应该是 超过1的,如果
如果超过1的话就会产生一些矛盾,所以这是UML中的组合关系。
但是这个组合关系显然是
不够完备的,为什么它会存在这种关系,它主要是从这个C++中来的。
C++中如果在一个对象嵌入另外一个对象的类型, 作为属性的话,它们之间就是一种很典型的
组合关系,就是因为这个部分,实际上只要
产生了一些整体的对象,这个部分对象就会
随之而来产生,并且这个整体一析构,这个部分跟着 也析构掉了。
所以呢 ,这个 这个组合关系呢,是一种
受约束的一种,一般的一种聚合关系。
这个从语义角度来看,它就是说定义它们生命周期是一致的。
从语法角度来看呢,它的这个作为 整体这端的多重性不能超过1,这是一种OCL,和上下文有关的
语法规则,但是呢我们如果说是放到一个自然 思维这个角度,或者从世界上来找一找有没有真正的一种
组合关系,这恐怕是很难找到的,因为很多的一种情况都是相对的,有些同学可能会说
人体器官和人之间构成组合关系,但是呢 我们知道很多情况下人体的器官
是可移植的,它这个人死了之后这个器官往往还可以活着,还可以放到另外一个
人体上发挥作用,因此它不是一个典型的一个整体部分关系,
不是一个典型的组合关系,还有一种情况就是这个
桌子,一个桌子由一个面和四条腿组成,它们之间是不是一种组合关系? 是吧,这个就是不同人有不同看法。
如果你是一个家具的使用者往往 从你的主观感受看,它,你
看到它,那它就是作为一个一个桌子就是一个桌面四条腿组成。
但是对于生产者来说,木工师傅来说,是吧?他在他
的眼中,这个桌子不是一开始就是四条腿一个桌面的,而是什么呢?
一开始先有的是四条腿,然后还有个一个桌面,把它们组合到一块
就是一个这个桌子,因为,因此从用户角度来看这可能是
一个组合关系,从那个工人师傅的这个角度来看它可能就是一种
一般的聚合关系,所以这个 在现实世界,这个组合能够
找到真正组合的这个例子是非常少的,它都是相对的。
没有真正绝对的这种组合关系,但是在软件世界 特别是在C++语言的世界里边,它就是一种非常严格的组合关系。
但是UML,这个把这种编程世界中
的东西作为一种现实世界中的一个描述,或者说这个本身它来自于软件世界,
现在把这个机制用来描述这个现实世界显然是
不够完备的,很多情况下是描述不清楚的,所以不同专业有不同的看法。
这里给出了一些例子,这个 另外一个软件世界中的例子,比如说这个一个
用户图形界面中的一个窗体和它的一些组成部分,像按钮啊、
handle、 工具栏,它们应该是组合关系。
这个海军和军舰之间是一种这个聚合关系,因为这个 它们不是同生同灭的。
这是它的一些性质,包括反对称性和传递性。
下面呢,我们再看一个思考题,这个就是说 这个我们这个平时经常玩游戏
这个会碰到这么一些场景,是吧?一开始游戏主角是一个
非常这个功能比较 单一的这么一个角色,只能在路上走。
用到各种武器,设备上简单的一些武器,当它接到一个什么灵丹妙药或者一种
特殊的一种机会,碰撞到一个法宝的话,它就 变成一种比较高级的一种角色,它可以腾云驾雾,可以
上天、 入地、 下海,这个,然后那个跑的也非常快,然后这个
使用的武器也非常先进,在这种情况下,如何对这种场景进行建模? 这时候呢你可以用三种方案,第一种方案呢是
就是说把人和神仙 作为游戏精灵,也就是游戏主角的那个
子类,用继承关系来表示,而第二种呢,就是说用这个组合,我们刚学到的这种
聚合关系来表示,因为它是变为人的身份和这个神仙的身份 这个方式。
第三种是既用 这个聚合关系又用组合关系,请问哪种方式比较好?
这个选择呢,其实 这个除了A之外,B和C都是可以的。
就是,为什么A不行呢?就是因为这个A是一种静态分类,而我们现在是一种动态分类。
那么什么是动态分类呢,是吧?动态分类就是说指的这个
一个对象在它的生命周期,从产生到消亡整个这个时间跨度中,
它可以变换不同的所属的类别,这叫动态分类。
而静态分类呢,就是说,一个对象从 它从生到死这个整个的这个时间跨度中,它不会变,改变这个分类
但现在就是一种这个跨越类别之间的一种分类 这个称之为动态,这个一个对象,它这个在生命周期内
它就在早期阶段属于一个类,到之后它属于另外一个类,因为它的这个特征会发生变化。
这种动态分类,实际上是不适合用 这个泛化关系来表示,为什么呢,就是因为
如果我们假如说用 A 这种方案的话 这个如何我实现变化,那么在这种机制
下我们如何实现变化呢,实际上我们如果说实现从一个神
人到神这样一个蜕变的话,那人首先呢,要根据
这个神仙这个类产生神仙一个实例,当然是它产生之后它里边属性啊
实际上是没有任何这个属性,需要我们把人的一些 与神仙类似或相同的一些属性复制到这个神仙
这个对象里边去,同时再把人这个对象虚构掉,这就 ok 了。
当然在这个产生的过程中呢,这个涉及到大量的这个
产生对象,在内存中分配空间,大批量地复制一些数据的这个过程
这会带来,不是说它不行,但是效率是非常低的,效率非常低,啊。
如果我们一个主角还好一些,如果涉及到很多主角同时变化,这时候你的效率会 带来大量的损失。
当然 B 和 C 为什么好呢,就是因为我们这个变成一种组合关系了
聚合关系,这样的话呢当我们身份发生变化的时候呢,是非常容易实现的。
无非就是 它将这个人的身份给它置为空,同时呢将这个神仙的身份
给它设置为一个既定的一个神仙这个对象就可以了 转换一个值就
ok了,所以这个 B 和 C 都是可以的。
但是这个 B 和 C 有什么区别呢? 就是当我们这个 C
这个方案更加适合多态这种情况,是吧? 当我们这个人和神都会这个走路,当然是他们
走路的行为发生变化,是吧?这个神仙可能跑得比较快,人跑得比较慢。
这个,这时候呢我们往往是,他们接口是相同的,但是我们由于它这个
我们给它装配不同的这个身份这个对象导致
调用它的这个,在调用的时候,它实际上是接口是完全一样的,这样对于我们编程的时候呢也是 非常好的。
所以因此,总体上来说 C 是 最优的一个方案。
它实用变化性,提高效率这方面,综合考虑是非常优秀的 因此,这就说明了一个什么道理呢,就是说这个动态分类,大概是我们
一般来说,不要用这个泛化关系来进行设计,或者说进行分析。
好下面我们再讨论一下这个聚合关系和组合关系的问题
聚合关系和组合关系刚才我们也讨论了一些,就是说这个组合关系啊,本身还是
相当地随意,相当地 应该说是这个不太属于自然的这种思维方式,但是
Martin Fowler 怎么看 的呢,Martin Fowler 的这个看法跟很多的这个专家看法正好是 反过来的。
Martin Fowler 的眼中啊,我们可以参考 Martin Fowler 写的一篇博客啊。
Martin Fowler 认为这个,组合关系,这个聚合关系是一种
不好的关系,因为它没有任何语义。
而这个聚合关系呢 这个组合关系啊,是一种有语义的,至少它能够表示一种约束条件
这个 Martin Fowler 为什么这样说呢,就是因为 他从编程序的这个角度来看,这个
面向对象的任何一种编程语言,大多数编程语言都没有实现这个 聚合关系,没有给出聚合关系的一种实现方式
所以,这个 就是说从 Martin Fowler
那个角度来看,他说这个语义是什么语义呢? 啊,他这个语义,并不是说我们这个动态语义。
如果从动态语义角度来看,它确实有语义 聚合就是表示这个整体部分关系,这就是一种这个
动态语义。
但是 Martin Fowler 说的这个,这种没有语义是什么意思呢,是指它没有静态 语义。
什么是静态语义我们以前提到过,静态语义就是一种上下文有关的语法规则
就是说,尽管你这个用这个黑菱形来,用白色这个菱形来表示这个整体部分关系 但是呢,你没法编程序。
你这个东西,你用这个 白菱形来表示这个类和类之间的关系,和你用一根线来表示这个
关系,到真正程序实现的时候,是一样的 没有什么区别,都是实际上为嵌入这个对方的
这个类型指针的一种这个 这种数据就可以了,是吧。
所以这时候呢,Martin Fowler 从这个角度来看,他
认为,他又引用这个 Jim R.
的话 说这个 aggregation 这种,这个
泛化关系,不是,聚合关系 就是一种什么呢,建模的安慰剂啊,万金油。
就是说这个 谁都可以用,然后呢就是,但是
大家都不知道它是什么具体的一些,实际的语义
每一个人用处的时候呢,每一个人这个用法也不一样,没有一个确定的指导规则 这是 Martin Fowler 的看法。
但相反来说,这个 Martin Fowler 认为这个 黑菱形,也就是组合关系,这种比较强的这种组合关系是有语义的。
他这个说的这个语义呢 就是说的静态语义。
为什么是静态语义呢,因为它表示的是一种 这个在静态上,尽管它也有这个动态的
语义,表示这个生命周期,但是它在静态上呢就表示 任何的一个,这个
组合关系,这个构成这个整体部分关系中的任何的一个
部分,如果说是一种,这个整体构成一种组合关系的话
那么它在整个生命周期的过程中只能属于 一个整体,不能属于多个整体。
用这种关系呢,就可以 非常好地描述这种,这个,这种 静态语义关系。
这是这个 Martin Fowler
的一个观点,和其他的观点呢 我们刚才说的那种观点不太一样,但是他们都反映了这个
很多专家普遍对这个黑菱形和白菱形啊,存在疑义。
就是 这是个需要我们值得这个关注的 一个问题
因此呢,另外一些专家,这是这个 Morton Winston
这个人本身不是我们这个软件领域的一个 学者,而是哲学领域的一个学者
联合一些人,试图通过跨学科跨领域的研究 来解决这个整体部分关系的一个本质的问题。
就是 整体部分关系,究竟怎么才能构成整体部分关系,有没有一个非常清晰的判断条件
或整体部分关系会不会有什么分类,而这个分类非常好,非常这个完备的这种分类方式 所以呢,Morton
Winston 等人呐 这个,认为,这个整体部分关系啊,要想进行分类的时候
必须要从三个性质来考虑,分别是构造性、 同质性、 不变性,这三个性质
来考察,通过它们的或有或无,来决定它到底是属于哪种 整体部分关系。
因此呢,在这个基础上他给出了大概有这个七种,这个不同的整体部分关系啊。
我们这个比如说,简单地看两种。
一种 叫组装·部分关系,这是他给出的一个名称,其实就是个代号,没有实际意义啊。
组装·部分关系具有构造性,不具有同质性,也不具有不变性
类似的一个例子,比如说我们平常所说的一个
计算机由这个主机、 键盘、 显示器组成,这就是一个
典型的组装·部分关系,也就是说组合 组合成为这个部分的,组合成为整体的
这些部分之间,是异构的,是非同质的 然后呢也不是不变的,就是说它们之间呢是
这个整体,不是说这个部分随着整体的产生而产生,随着部分的消亡而消亡
另外呢就是,它们之间具有构造性。
什么是构造性呢,就是它们整体大于部分之和,啊。
它们这些功能加起来之后 它们的这个整体的功能,不仅是它们的部分之和,而且要比
它们部分之和更大,跟我们以前讲的系统概念是非常一致的
结构系统,它们都是一种具有涌现性,这个也体现 出来了。
还有一些什么,这个面包 是由面粉、 糖、 黄油组成的,啊这是另外一种关系。
这种关系呢,它是这个不具有构造性,因为组合起来之后呢,它们没有结构
它们之间就丧失了结构,它们就混合到一块,这个就 不是一种可以相互交换物质和信息的一种系统
这交换已经混合均匀了,是非耗散系统,因此它没有整体性。
这个也没有同质性,啊,这个, 但是有不变性,啊就是说这个
这时候呢这个整体啊,这个一但混合好了之后就不容易 再把它们分开,很难把它们分开。
所以这个是一种,另外一种关系。
啊,还有是其他的一些关系。
但是他搞了这个 七种关系之后呢,在 UML
中没有这个做出 相应的调整,但是这有什么用呢,就是为了我们在识别
帮助我们识别整体关系的时候有一个非常好的一个把握,如果我们按照这个七种
组合关系给出的一些判断条件来识别组合关系,可以使我们 这个比较有效地识别一些整体部分关系。
当然其他的关系呢我们这儿就不一一介绍了, 这是识别策略,我们可以发现这个
整体部分的识别策略呢,完全可以借助于刚才我们讲的这 这几类,我们就是从这几类这个着眼点来考虑识别整体部分关系。
跟我们课本儿上,啊教材上讲的是基本上是相似的。
这个这是识别策略,这个之后呢我们要进行这个审查和筛选,是吧?
这个审查和筛选呢就是看是不是属于问题域和系统责任
是否真正有一个以上的特征,是否有明显的 整体部分关系,这儿我们这个就不详细说了,这个大家可以看
这个参考教材。