类间关系

在类图中,除了需要描述单独的类的名称、属性和操作外,我们还需要描述类之间的联系,因为没有类是单独存在的,它们通常需要和别的类协作,创造比单独工作更大的语义。在UML类图中,关系用类框之间的连线来表示,连线上和连线端头处的不同修饰符表示不同的关系。类之间的关系有继承(泛化)、关联、聚合和组合。

(1)继承:指的是一个类(称为子类)继承另外的一个类(称为基类)的功能,并增加它自己的新功能的能力,继承是类与类之间最常见的关系。类图中继承的表示方法是从子类拉出一条闭合的、单键头(或三角形)的实线指向基类。例如,图3.2给出了MFC中 CObject类和菜单类CMenu的继承关系。

     图3.2 类的继承

类的继承在C++中呈现为:

class B { }
class A : public B{ }

(2)关联:指的是模型元素之间的一种语义联系,是类之间的一种很弱的联系。关联可以有方向,可以是单向关联,也可以是双向关联。可以给关联加上关联名来描述关联的作用。关联两端的类也可以以某种角色参与关联,角色可以具有多重性,表示可以有多少个对象参与关联。可以通过关联类进一步描述关联的属性、操作以及其他信息。关联类通过一条虚线与关联连接。对于关联可以加上一些约束,以加强关联的含义。

关联在C++中呈现为:

class A{...}
class B{ ...}
A::Function1(B &b) //或A::Function1(B b) //或A::Function1(B *b)

即一个类作为另一个类方法的参数。

(3)聚合:指的是整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构。从而找出一些组成类,该整体类和组成类之间就形成了聚合关系。例如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力***潜艇等。需求描述中“包含”、“组成”、“分为…部分”等词常意味着聚合关系。

(4)组合:也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在。部分对象与整体对象之间具有共生死的关系。

聚合和组合的区别在于:聚合关系是“has-a”关系,组合关系是“contains-a”关系;聚合关系表示整体与部分的关系比较弱,而组合比较强;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。

我们用浅显的例子来说明聚合和组合的区别。“国破家亡”,国灭了,家自然也没有了,“国”和“家”显然也是组合关系。而相反的,计算机和它的外设之间就是聚合关系,因为它们之间的关系相对松散,计算机没了,外设还可以独立存在,还可以接在别的计算机上。在聚合关系中,部分可以独立于聚合而存在,部分的所有权也可以由几个聚合来共享,比如打印机就可以在办公室内被广大同事共用。

在C++语言中,从实现的角度讲,聚合可以表示为:

class A {...}
class B { A* a; .....}

即类B包含类A的指针;

而组合可表示为:

class A{...}
class B{ A a; ...}

即类B包含类A的对象。

准确的UML类图中用空心和实心菱形对聚合和组合进行了区分。

          图3.4 聚合和组合

 

聚合,关联,组合 是对象之间的三种关系。从某种意义上说,继承是一种类的纵向关系,而聚合,关联,组合是对象的横向关系。


其关系强弱为 关联<聚合<组合

 

关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的,例如一个公司包含了很多员工,其实现上是差不多的。聚合和组合的区别则在语义和实现上都有差别,组合的两个对象之间其生命期有很大的关联,被组合的对象是在组合对象创建的同时或者创建之后创建,在组合对象销毁之前销毁。一般来说被组合对象不能脱离组合对象独立存在,而且也只能属于一个组合对象,例如一个文档的版本,必须依赖于文档的存在,也只能属于一个文档。聚合则不一样,被聚合的对象可以属于多个聚合对象,例如一个员工可能可以属于多个公司。

我想举个通俗的例子。
你和你的心脏之间是composition关系(心脏只属于自己)
你和你买的书之间是aggregation关系(书可能是别人的)
你和你的朋友之间是association关系

聚合与组合的区别:聚合∶分散的聚集到一起 组合∶几个独立部分组成的整体 由上可见,聚合就像将不同的水果放到一个玻璃果盘里,玻璃果盘摔坏,并不影响水果。

1.实例化(依赖) 
A将B作为局部变量进行使用. 
程序1 
void   A::foo() 

        B   b; 
        b.SomeMethod(); 


2.关联 
A与B存在一定的关系.   这里只考虑单向导航.   关联在代码中有多种表现形式. 
第一种,   作为参数: 
程序2 
void   A::foo(B&   b)   //   (B*   b)   or   (B   b) 

        b.SomeMethod(); 


第二种,   作为成员变量: 
程序3 
class   A 

public: 
        A(B&   b) 
        { 
                b_   =   b; 
        } 

        void   foo() 
        { 
                b_.SomeMethod(); 
        } 
private: 
        B&   b_;   //   B*   b_ 
}; 

3.聚合 
聚合是一种特殊的关联,   聚合更明确指出聚合的主体具有整体-部分关系.   代码的表现形式见程序3. 


4.组合 
组合是一种特殊的聚合,   组合中的某个主体控制着另外一个主体的生命周期,而且他们还存在整体-部分关系. 
程序4 
class   A 

public: 
        A() 
        { 
                b_   =   new   B; 
        } 

        ~A() 
        { 
                delete   b_; 
                b_   =   NULL; 
        } 

        void   foo() 
        { 
                b_-> SomeMethod(); 
        } 
private: 
        B*   b_; 
};