泛化(Generalization)
在上图中,空心的三角表示继承关系(类继承),在UML的术语中,这种关系被称为泛化(Generalization)。Person(人)是基类,Teacher(教师)、Student(学生)、Guest(来宾)是子类。
若在逻辑上B是A的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性。
例如,教师是人,Teacher 是Person的“一种”(a kind of )。那么类Teacher可以从类Person派生(继承)。
如果A是基类,B是A的派生类,那么B将继承A的数据和函数。
如果类A和类B毫不相关,不可以为了使B的功能更多些而让B继承A的功能和属性。
若在逻辑上B是A的“一种”(a kind of ),则允许B继承A的功能和属性。
聚合(组合)
若在逻辑上A是B的“一部分”(a part of),则不允许B从A派生,而是要用A和其它东西组合出B。
例如,眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头(Head)的一部分,所以类Head应该由类Eye、Nose、Mouth、Ear组合而成,不是派生(继承)而成。
聚合的类型分为无、共享(聚合)、复合(组合)三类。
聚合(aggregation)
上面图中,有一个菱形(空心)表示聚合(aggregation)(聚合类型为共享),聚合的意义表示has-a关系。聚合是一种相对松散的关系,聚合类B不需要对被聚合的类A负责。
组合(composition)
这幅图与上面的唯一区别是菱形为实心的,它代表了一种更为坚固的关系——组合(composition)(聚合类型为复合)。组合表示的关系也是has-a,不过在这里,A的生命期受B控制。即A会随着B的创建而创建,随B的消亡而消亡。
依赖(Dependency)
这里B与A的关系只是一种依赖(Dependency)关系,这种关系表明,如果类A被修改,那么类B会受到影响。
组合或是聚合,你得从思想上去判断,而不能从实现上判断,因为它们两个的实现,可能是及其接近的。
首先要说明的是概念。《设计模式》一书中没有使用“组合”这个概念,而UML表示中一般没有使用“相识”这个概念。但是两者实际上存在如下的对应关系:
/////////////////////////////////////////////
《设计模式》 UML 表示的意义
聚合 组合 聚合/组合 对象和其所有者具有相同的生命周期
相识 聚合 一个对象仅仅知道另一个对象
/////////////////////////////////////////////
不过,这个对应关系也不是绝对的。
1、 UML中还有一种关系叫“关联”,《设计模式》中对这种关系的说明很准确:“OMT还定义了类间的关联(association)关系,以类间的一条线来表示。关联关系是双向的。虽然在分析阶段这种关系是适用的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引用或指针。对象引用本身就是有向的,更适合表达我们所讨论的那种关系。”也可以说“关联”到代码的映射是一对多的,并且这种一对多的关系会影响到模式的选择。
2、 UML中“组合”“聚合”的概念是用来表示对象的静态结构的,因此我们可以这样认为:“组合”就是用成员变量实现的,而“聚合”就是用指向某个对象的指针来实现的。当然,这里略去了对成员函数的参数的考虑。
3、 《设计模式》中对“聚合”和“相识”的关系描述如下:“C++中,聚合可以通过定义表示真正实例的成员变量来实现,但更通常的是将这些成员变量定义为实例指针或引用;相识也是以指针或引用来实现。”“从根本上讲,是聚合还是相识是由你的意图而不是由显式的语言机制决定的。”通过这两个说明,可以看到《设计模式》中认为“聚合”和“相识”关系是运行时的动态特性,从这点上来说和UML有本质的区别。另外,《设计模式》中对这两者动态特性描述如下:“聚合关系使用较少且比相识关系更持久;而相识关系则出现频率较高,但有时只存在于一个操作期间,相识也更具动态性,使得它在源代码中更难被辨别出来。”显然,这种描述只是说到了量的问题,而没有说到质的问题,从这里还是看不出“聚合”和“相识”到底在运行时有什么本质不同。