在UML中,我们可以使用不同的关系来表示不同类型的元素之间的联系。这些关系包括关联、依赖、聚合、组合、泛化和实现。下面我们将分别解释这些关系的含义:
1. 关联(Association):关联表示模型元素及链接实例之间的连接,用一条实线来表示。
2. 依赖(Dependency):依赖表示一个元素以某种方式依赖于另一个元素,用一条虚线加箭头来表示。例如,类A使用到了类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A。
3. 聚合(Aggregation):聚合表示整体与部分的关系,用一条实线加空心菱形来表示。部分事物的对象可以属于多个聚合对象,部分事物的对象与聚合对象的生存期无关。
4. 组成(Composition):组成表示整体与部分有一关系,用一条实线加实心菱形来表示。组成关系不仅控制着成员对象的行为,而且控制着成员对象的创建和解构。
5. 泛化(Generalization):泛化表示一般与特殊的关系,用一条实线加空心箭头来表示。例如,子类继承父类的属性和方法。
6. 实现(Implementation):实现表示类与接口的关系,用一条虚线加空心箭头来表示。实现关系描述了类是如何实现其接口的。
在UML中,泛化关系和实现关系又统称为一般关系。一般关系表现为继承或实现(is a)。关联关系、聚合关系、合成(聚合)/组合关系表现为成员变量(has a),依赖关系表现为函数中的参数(use a)。
根据关系之间的强弱程度,从弱到强排列为:没关系 > 依赖 > 关联 > 聚合 > 组合。
在UML中讲到类之间的关系时,有以下几种:
- 依赖关系:类之间使用关系;
- 泛化关系:类之间一般/特殊关系;
- 关联关系:对象之间结构关系;
- 实现关系:类中规格说明和实现之间关系。
聚合与组合是不容易混淆的概念:
1. 聚合(Aggregation):一种特殊类型的关联,表示整体与部分关系的关联。描述了“has a”的关系。部分事物的对象可以属于多个聚合对象,部分事物的对象与聚合对象的生存期无关。
2. 组合(Composite):聚合关系中的一种特殊情况,是更强形式的聚合,又称强聚合。成员对象的生命周期取决于组合的生命周期。组合不仅控制着成员对象的行为,而且控制着成员对象的创建和解构。
在UML中,抽象依赖、授权依赖和绑定依赖是四种基本的依赖类型。
- 使用(Usage)依赖:表示客户使用提供者提供的服务以实现它的行为。
- 抽象(Abstraction)依赖:表示使用者和提供者之间的关系。
- 授权(Permission)依赖:表示提供者可以规定一定的客户的权利来对提供者控制和限制。
- 绑定(Binding)依赖:较高级的依赖类型,用于绑定模板以创建新的模型元素。
使用依赖和绑定依赖在同一语义层上将很强的语义包括进元素内。它们必须连接模型同一层的元素。
关联类:通过关联对象类可以进一步描述关联的属性、操作,及其它信息。关联对象类是一个关联也是一个类,关联类的图标用一条虚线连接到关联线上。(简而言之:关联类就是通过一个类将其他两个类关联起来。)
自反关联:一个对象类与本身的关联,一个类的两个实例集间的关联。
N元关联:意如其名。
继承是实现泛化的一种机制。在此不详细说明继承,继承分为单继承和多继承。单继承是指一个子类只从一个父类继承属性和方法,形成层次结构;多继承是指一个子类可以从多个父类继承属性和方法,形成网格结构。继承有传递性。继承中重要的概念有重载、覆盖(重写)、多态等。
在最简单的形式中,一个对象仅属于一个类,许多面向对象的语言有这种限制。一个对象仅属于一个类并没有逻辑上的必要性,我们只要从多个角度同时观察一下真实世界的对象就可以发现这一点。在UML更概括的形式中,一个对象可以有一个或多个类。对象看起来就好像它属于一个隐式类,而这个类是每个直接父类的子类——多重继承可以免去再声明一个新类,这可提高效率。
静态与动态类元:在最简单的形式中,一个对象在被创建后不能改变它的类。我们再次说明,这种限制并没有逻辑上的必要性,而是最初目地是使面向对象编程语言的实现更容易些。在更普遍的形式下,一个对象可以动态改变它的类,这么做会得到或失去一些属性或关联。如果对象失去了它们,那么在它们中的信息也就失去了并且过后也不能被恢复,哪怕这个对象变回了原来的类。如果这个对象得到了属性或关联,那么它们必须在改变时就初始化,就像初始化一个新对象一样。当多重分类和动态分类一起使用时,一个对象就可以在它的生命期内得到或失去类。动态类有时被称作角色或类型。一个常见的建模模式是每个对象有一个唯一的静态的固有类(即不能在对象的生命期内改变的类),加上零个或多个可以在对象生命期内加入或移走的角色类。固有类描述了这个对象的基本特性,而角色类描述了暂时的特性。虽然许多程序设计语言不支持类声明中的多重动态分类,然而它仍然是一个很有用的建模概念,并且可以被映射到关联上。
实现(realization):规格说明和其实现之间的关系。UML中实现关系通常在两种情况下被使用:在接口与实现该接口的类之间;
在用例以及实现该用例的协作之间,存在关系性。这种关系性主要体现在关联(Association Relationship)和依赖(Dependency Relationship)两个方面。
关联(Association Relationship)具有以下特点:
1. 关联有双向与单向之分。类A与类B双向关联可以是A与B相互可以作为对方的一个attribute(属性),单向的话,就指其中一个类作为另一个类中的 attribute(属性)。
2. 依赖就只有单向的。不存在attribute(属性)的问题,例如类A依赖类B,表示在类A中有三种类B的使用方法:一是类B是全局的,二是类B在类A中实例化,三是类B作为参数被传递。
依赖(Dependency Relationship)具有以下特点:
1. 关联是一种结构关系,表现为一个对象能够获得另一个对象的实例引用并调用它的服务(即使用它)。
2. 依赖是一种使用关系,表现为一个对象仅仅是调用了另一个对象的服务。依赖是比关联弱的关系,体现在生成的代码中。
在Java中,关联关系是通过实例变量而实现的,同时关联可以是双向的,关联可以有一对多的关系。依赖在Java语言中体现为局部变量、方法参数,以及对静态的方法调用。依赖总是单向的。
关联的主要目的是要得知外部对象的属性和方法。依赖的主要目的是将对象或类信息作为外部状态传进类中形成外蕴。
泛化和实现关系都可以将一般描述与具体描述联系起来。但它们不同之处在于:泛化将同一语义层上的元素连接起来,并且通常在同一模型内。实现关系则将不同语义层内的元素连接起来,通常建立在不同的模型内。组合就是强聚合。通俗来讲:组合是缺一不可,聚合就没有这种强制要求了。