随笔- 29  文章- 5  评论- 437 

网上关于此类的讨论非常多,发现对于该问题的理解各有各的说法,而各个说法中又相去甚远。通过浏览这些讨论以及对《O'Reilly - UML 2.0 In A Nutshell (2007)》的参考,发表一下自己的看法

类间关系有很多种,在大的类别上可以分为两种:纵向关系、横向关系。

纵向关系就是继承关系,它的概念非常明确,也成为OO的三个重要特征之一,这里不过多的讨论。

横向关系较为微妙,按照UML的建议大体上可以分为四种:

  1. 依赖    (Dependency)
  2. 关联    (Association)
  3. 聚合    (Aggregation)
  4. 组合    (Composition)

它们的强弱关系是没有异议的:依赖 < 关联 < 聚合 < 组合

然而它们四个之间的差别却又不那么好拿捏,需要好好体会。

  1. 依赖
    • UML表示法:虚线 + 箭头
    • 关系:" ... uses a ..."
    • 此关系最为简单,也最好理解,所谓依赖就是某个对象的功能依赖于另外的某个对象,而被依赖的对象只是作为一种工具在使用,而并不持有对它的引用。
    • 典型的例子很多,比如:
      class Human
      {
          public void breath()
          {
              Air freshAir = new Air();
              freshAir.releasePower();
          }
          public static void main()
          {
              Human me = new Human();
              while(true)
              {
                  me.breath();
              }
          }
      }

      class Air
      {
          public void releasePower()
          {
              //do sth.
          }
      }
       
    • 释义:一个人自创生就需要不停的呼吸,而人的呼吸功能之所以能维持生命就在于吸进来的气体发挥了作用,所以说空气只不过是人类的一个工具,而人并不持有对它的引用。
  2. 关联
    • UML表示法:实线 + 箭头
    • 关系:" ... has a ..."
    • 所谓关联就是某个对象会长期的持有另一个对象的引用,而二者的关联往往也是相互的。关联的两个对象彼此间没有任何强制性的约束,只要二者同意,可以随时解除关系或是进行关联,它们在生命期问题上没有任何约定。被关联的对象还可以再被别的对象关联,所以关联是可以共享的。
    • 典型的例子很多,比如:
      class Human
      {
          ArrayList friends = new ArrayList();
          public void makeFriend(Human human)
          {
              friends.add(human);
          }
          public static void main()
          {
              Human me = new Human();
              while(true)
              {
                  me.makeFriend(mySchool.getStudent());
              }
          }
      }
    • 释义:人从生至死都在不断的交朋友,然而没有理由认为朋友的生死与我的生死有必然的联系,故他们的生命期没有关联,我的朋友又可以是别人的朋友,所以朋友可以共享。
  3. 聚合:  
    • UML表示法:空心菱形 + 实线 + 箭头
    • 关系:" ... owns a ..."
    • 聚合是强版本的关联。它暗含着一种所属关系以及生命期关系。被聚合的对象还可以再被别的对象关联,所以被聚合对象是可以共享的。虽然是共享的,聚合代表的是一种更亲密的关系。
    • 典型的例子很多,比如:
      class Human
      {
          Home myHome;
          public void goHome()
          {
              //在回家的路上
              myHome.openDoor();
              //看电视
          }
          public static void main()
          {
              Human me = new Human();
              while(true)
              {
                  //上学
                  //吃饭
                  me.goHome();
              }
          }
      }
       
    • 释义:我的家和我之间具有着一种强烈的所属关系,我的家是可以分享的,而这里的分享又可以有两种。其一是聚合间的分享,这正如你和你媳妇儿都对这个家有着同样的强烈关联;其二是聚合与关联的分享,如果你的朋友来家里吃个便饭,估计你不会给他配一把钥匙。
  4. 组合
    • UML表示法:实心菱形 + 实线 + 箭头
    • 关系:" ... is a part of  ..."
    • 组合是关系当中的最强版本,它直接要求包含对象对被包含对象的拥有以及包含对象与被包含对象生命期的关系。被包含的对象还可以再被别的对象关联,所以被包含对象是可以共享的,然而绝不存在两个包含对象对同一个被包含对象的共享。
    • 典型的例子很多,比如:
      class Human
      {
          Heart myHeart = new Heart();
          public static void main()
          {
              Human me = new Human();
              while(true)
              {
                  myHeart.beat();
              }
          }
      }
    • 释义:组合关系就是整体与部分的关系,部分属于整体,整体不存在,部分一定不存在,然而部分不存在整体是可以存在的,说的更明确一些就是部分必须创生于整体创生之后,而销毁于整体销毁之前。部分在这个生命期内可以被其它对象关联甚至聚合,但有一点必须注意,一旦部分所属于的整体销毁了,那么与之关联的对象中的引用就会成为空引用,这一点可以利用程序来保障。心脏的生命期与人的生命期是一致的,如果换个部分就不那么一定,比如阑尾,很多人在创生后的某个时间对其厌倦便提前销毁了它,可它和人类的关系不可辩驳的属于组合。
      在UML中存在一种特例,就是允许被包含对象在包含对象销毁前转移给新的对象,这虽然不自然,但它给需要心脏移植的患者带来了福音。
 posted on 2008-02-27 12:12 floodpeak 阅读(2424) 评论(22)  编辑 收藏 网摘 所属分类: 面向对象

#1楼    回复  引用  查看    
 金色海洋(jyk)       | 2008-02-27 12:32
这么复杂呀。占个sf。
#2楼    回复  引用  查看    
 毁于随       | 2008-02-27 12:51
很形象.不错.
#3楼    回复  引用  查看    
 任力       | 2008-02-27 13:04
讲的不错,谢谢分享。
理论性很强

#4楼    回复  引用    
 努力学习![未注册用户] | 2008-02-27 14:19
聚合是这个意思吗?
#5楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-27 14:33
@金色海洋(jyk)
@毁于随
@任力
@努力学习!
谢谢关注

#6楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-27 14:35
@努力学习!
这是我在阅读参考资料和网上讨论后结合自己的理解总结出来的,欢迎你谈谈你的理解

#7楼    回复  引用  查看    
 非我       | 2008-02-27 15:44
看了lz的文章,总结下自己的看法,依赖是A暂时使用B,关联是A仅持有B的引用,但聚合和组合看起来都是A完全持有B,没啥区别啊?
#8楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-27 16:25
@非我
感谢关注
首先要说明的是除了依赖关系外,其余的三个在形式上是基本一致的,它们都是在外部类中包含了一个对内部类的引用
聚合是一种强关联,也就是说聚合就是关联,因为它的关系比普通的关联强,而将其抽出来,用来进行强调
而组合则要求更加强烈,被组合的对象就是它的一部分,对生命期有严格的限制,但是表现的形式很有可能是与关联(包括聚合)一致的,之所以说是很有可能,原因在于有的时候你可以把被组合类直接写为一个内部类来通过语法来限制其他类对它的访问,当然这不是必须的,而且我也不习惯这样做
建议通过各种关系的英文解释来理解,比如关联是has a,而聚合却是owns a,关系强了,组合就成了is a part of,关系更强烈了
再补充一句,关联的两个对象往往是平等的,而聚合和组合的两个对象就不平等了

#9楼    回复  引用  查看    
 Gao Zhongfa       | 2008-02-27 18:00
基础概念讲的挺明白,容易懂
学习了。

#10楼    回复  引用  查看    
 Anders Cui       | 2008-02-27 18:02
@floodpeak
我感觉聚合和组合都是表示“is a part of”的关系
组合相比于聚合来说
一般体现在“整体要负责部分的生命周期”

#11楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-27 21:03
@Gao Zhongfa
@Anders Cui
谢谢关注

#12楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-27 21:09
@Anders Cui
我这里的说法是出自我在文中提到的那本书,是O'Reilly出版的,还算权威,当然这个仁者见仁,外在的表现形式都是相同的,他们的界线不是极为明显的
比如The car owns four wheels.和The wheel is a part of the car.都是可以的

#13楼    回复  引用    
 Intermapper[未注册用户] | 2008-02-28 10:27
有些复杂!先收藏了!
#14楼    回复  引用    
 Paddle[未注册用户] | 2008-02-28 11:53
很形象,解释得好好~ 谢谢楼主~~ give you a kiss~~:>
#15楼    回复  引用    
 在线代理[未注册用户] | 2008-02-28 12:15
很贴切的比喻,这个东东好。
#16楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-28 13:48
@Intermapper
@Paddle
@在线代理
谢谢支持,哈哈

#17楼    回复  引用  查看    
 ∈鱼杆       | 2008-02-28 14:33
组合关系是不是在构造函数中写更合理.
class Human
{
Heart myHeart
public Human()
{
myHeart = new Heart();
}

public static void main()
{
Human me = new Human();
while(true)
{
myHeart.beat();
}
}
}

#18楼[楼主]    回复  引用  查看    
 floodpeak       | 2008-02-28 14:50
@∈鱼杆
我的理解是和个人习惯有关系,毕竟这两种写法在这里效果是一样的

#19楼    回复  引用    
路过
#20楼    回复  引用    
 衢州婚庆[未注册用户] | 2008-02-28 15:29
衢州
#21楼    回复  引用  查看    
 MS的明天       | 2008-02-29 11:20
写的很不错,希望看到后续
#22楼    回复  引用  查看    
 Ryanism       | 2008-11-30 16:23
组合是关系当中的最强版本,它直接要求包含对象对被包含对象的拥有以及包含对象与被包含对象生命期的关系。被包含的对象还可以再被别的对象关联,所以被包含对象是可以共享的,然而绝不存在两个包含对象对同一个被包含对象的共享。
----------------------

你好,有一点不太明白,想请教一下:

请问这里的"所以被包含对象是可以共享的,然而绝不存在两个包含对象对同一个被包含对象的共享。"是怎么理解的? 这句话是不是有点矛盾?

谢谢~




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1083533




相关文章:

相关链接: