UML类图与类的关系详解

UML类图与类的关系详解

2011-04-21 来源:网络

在画类图的时候,理清类和类之间的关系是重点。类的关系有泛化(Generalization)、实现(Realization)、依赖(Dependency)和关联(Association)。其中关联又分为一般关联关系和聚合关系(Aggregation),合成关系(Composition)。下面我们结合实例理解这些关系。

基本概念

类图(Class Diagram): 类图是面向对象系统建模中最常用和最重要的图,是定义其它图的基础。类图主要是用来显示系统中的类、接口以及它们之间的静态结构和关系的一种静态模型。

类图的3个基本组件:类名、属性、方法。 

UML类图与类的关系详解_第1张图片

泛化(generalization):表示is-a的关系,是对象之间耦合度最大的一种关系,子类继承父类的所有细节。直接使用语言中的继承表达。在类图中使用带三角箭头的实线表示,箭头从子类指向父类。

UML类图与类的关系详解_第2张图片

实现(Realization):在类图中就是接口和实现的关系。这个没什么好讲的。在类图中使用带三角箭头的虚线表示,箭头从实现类指向接口。

UML类图与类的关系详解_第3张图片

依赖(Dependency):对象之间最弱的一种关联方式,是临时性的关联。代码中一般指由局部变量、函数参数、返回值建立的对于其他对象的调用关系。一个类调用被依赖类中的某些方法而得以完成这个类的一些职责。在类图使用带箭头的虚线表示,箭头从使用类指向被依赖的类。

UML类图与类的关系详解_第4张图片

关联(Association) : 对象之间一种引用关系,比如客户类与订单类之间的关系。这种关系通常使用类的属性表达。关联又分为一般关联、聚合关联与组合关联。后两种在后面分析。在类图使用带箭头的实线表示,箭头从使用类指向被关联的类。可以是单向和双向。

UML类图与类的关系详解_第5张图片

聚合(Aggregation) : 表示has-a的关系,是一种不稳定的包含关系。较强于一般关联,有整体与局部的关系,并且没有了整体,局部也可单独存在。如公司和员工的关系,公司包含员工,但如果公司倒闭,员工依然可以换公司。在类图使用空心的菱形表示,菱形从局部指向整体。

UML类图与类的关系详解_第6张图片

组合(Composition) : 表示contains-a的关系,是一种强烈的包含关系。组合类负责被组合类的生命周期。是一种更强的聚合关系。部分不能脱离整体存在。如公司和部门的关系,没有了公司,部门也不能存在了;调查问卷中问题和选项的关系;订单和订单选项的关系。在类图使用实心的菱形表示,菱形从局部指向整体。

UML类图与类的关系详解_第7张图片

多重性(Multiplicity) : 通常在关联、聚合、组合中使用。就是代表有多少个关联对象存在。使用数字..星号(数字)表示。如下图,一个割接通知可以关联0个到N个故障单。

UML类图与类的关系详解_第8张图片

聚合和组合的区别

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

实例分析

联通客户响应OSS。系统有故障单、业务开通、资源核查、割接、业务重保、网络品质性能等功能模块。现在我们抽出部分需求做为例子讲解。

大家可以参照着类图,好好理解。

UML类图与类的关系详解_第9张图片

1. 通知分为一般通知、割接通知、重保通知。这个是继承关系。

2. NoticeService和实现类NoticeServiceImpl是实现关系。

3. NoticeServiceImpl通过save方法的参数引用Notice,是依赖关系。同时调用了BaseDao完成功能,也是依赖关系。

4. 割接通知和故障单之间通过中间类(通知电路)关联,是一般关联。

5. 重保通知和预案库间是聚合关系。因为预案库可以事先录入,和重保通知没有必然联系,可以独立存在。在系统中是手工从列表中选择。删除重保通知,不影响预案。

6. 割接通知和需求单之间是聚合关系。同理,需求单可以独立于割接通知存在。也就是说删除割接通知,不影响需求单。

7. 通知和回复是组合关系。因为回复不能独立于通知存在。也就是说删除通知,该条通知对应的回复也要级联删除。

经过以上的分析,相信大家对类的关系已经有比较好的理解了。大家有什么其它想法或好的见解,欢迎拍砖。

PS:还是那句话:以上类图用Enterprise Architect 7.5所画,在此推荐一下EA,非常不错。可以替代Visio和Rose了。Visio功能不够强大,Rose太重。唯有EA比较合适。

 

 

========================================

 

 

箭头:

指向父类或接口。
指向依赖物。
指向子元素。

 

 

 

继承、实现是三角型箭头,其他都为箭头

组合、聚合都有一个菱形端,且都为实线,其他都无菱形端

继承是实线,实现是虚线

关联是实线

依赖是虚线

 

        一般化关系/泛化/继承

        实现

 

        关联

        聚合

            组合/合成 

 

        依赖

 

传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系:

     泛化:表示类与类之间的继承关系、接口与接口之间的继承关系;

     实现:表示类对接口的实现;

     依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识关系”,只在某个特定地方(比如某个方法体内)才有关系。

     关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”;具体到代码可以用实例变量来表示;

     聚合:属于是关联的特殊情况,体现部分-整体关系,是一种弱拥有关系;整体和部分可以有不一样的生命周期;是一种弱关联;

 

     组合:属于是关联的特殊情况,也体现了体现部分-整体关系,是一种强“拥有关系”;整体与部分有相同的生命周期,是一种强关联;

 

1. 类(Class

一般包含3个组成部分。第一个是类名;第二个是属性(attributes);第三个是该类提供的方法(类的性质可以放在第四部分;如果类中含有内部类,则会出现第五个组成部分)。类名部分是不能省略的,其他组成部分可以省略。

 

类名书写规范:正体字说明类是可被实例化的,斜体字说明类为抽象类。

 

属性和方法书写规范:修饰符 [描述信息] 属性、方法名称 [参数] [:返回类型|类型]

 

属性和方法之前可附加的可见性修饰符:

 

加号(+)表示public;减号(-)表示private#号表示protected;省略这些修饰符表示具有package(包)级别的可见性。

      如果属性或方法具有下划线,则说明它是静态的。

         描述信息使用 << 开头和使用 >> 结尾。

         类的性质是由一个属性、一个赋值方法和一个取值方法组成。书写方式和方法类似。

1

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20class%20TaxCalculator%0A%7B%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20private%20longtaxRate%20%3B%0A%20%20%20%20%20%20%20%20%20private%20intsalary%3B%0A%0A%20%20%20%20%20%20%20%20%20public%20TaxCalculator(long%20taxRate)%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20this.taxRate%20%3D%20taxRate%20%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20public%20long%20countTax()%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20taxRate*salary%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20public%20int%20getSalary()%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20salary%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20public%20void%20setSalary(int%20salary)%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20this.salary%20%3D%20salary%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%0A%7D%20" wmode="transparent"> 收藏代码

  1. public class TaxCalculator  

  2. {        

  3.          private longtaxRate ;  

  4.          private intsalary;  

  5.   

  6.          public TaxCalculator(long taxRate)  

  7.          {  

  8.                    this.taxRate = taxRate ;  

  9.          }  

  10.   

  11.         public long countTax()  

  12.          {  

  13.                   return taxRate*salary;  

  14.          }  

  15.   

  16.          public int getSalary()  

  17.          {  

  18.                    return salary;  

  19.          }  

  20.   

  21.          public void setSalary(int salary)  

  22.          {  

  23.                    this.salary = salary;  

  24.          }  

  25.   

  26. }   

  

TaxCalculator

-taxRate:long

+TaxCalculator(a:long)

+countTax():long

salary:long

 

       
2. 
包(Package

 

包是一种常规用途的组合机制。UML中的一个包直接对应于Java中的一个包。在Java中,一个包可能含有其他包、类或者同时含有这两者。进行建模时,通常使用逻辑性的包,用于对模型进行组织;使用物理性的包,用于转换成系统中的Java包。每个包的名称对这个包进行了惟一性的标识。:

 


UML类图与类的关系详解_第10张图片
 

3. 接口(Interface

 

接口是一系列操作的集合,它指定了一个类所提供的服务。它直接对应于Java中的一个接口类型。接口的表示有大概两种方式。具体画法见下例:

 

例:

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20interface%20TaxCalculator%0A%7B%0A%20%20%20%20%20%20%20%20%20public%20long%20countTax()%3B%0A%0A%20%20%20%20%20%20%20%20%20public%20int%20getSalary()%3B%0A%0A%20%20%20%20%20%20%20%20%20public%20void%20setSalary(int%20salary)%3B%0A%0A%7D%20" wmode="transparent"> 收藏代码

  1. public interface TaxCalculator  

  2. {  

  3.          public long countTax();  

  4.   

  5.          public int getSalary();  

  6.   

  7.          public void setSalary(int salary);  

  8.   

  9. }   

  

画法一:

 


UML类图与类的关系详解_第11张图片
 

 

      画法二 :    

 

Interface

TaxCalculator

+countTax():long

+getSalary():int

+setSalary()

 
 

4. 关系

 

常见的关系有:

一般化关系(继承)、

实现关系(接口实现)、

聚合关系、

合成关系、

依赖关系。

请注意不同关系在图中连线表示的不同。

 

4.1一般化关系(Generalization

 

在有的书籍和资料中也叫做泛化关系

 

       一般化关系表示类与类、接口与接口之间的继承关系。关系中的箭头由子类指向父类。在Java中,用extends关键字来直接表示这种关系。

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20abstract%20class%20Employee%7B%0A%0A%7D%0A%0Apublic%20class%20Programmer%20extends%20Employee%7B%0A%0A%7D%20" wmode="transparent"> 收藏代码

  1. public abstract class Employee{  

  2.   

  3. }  

  4.   

  5. public class Programmer extends Employee{  

  6.   

  7. }   

 继承: 

 



 

 

4.2实现(Realization

 

实例关系指定两个实体之间的一个合同。换言之,一个实体定义一个合同,而另一个实体保证履行该合同。关系中的箭头由实现接口的类指向被实现的接口。在Java中,实现关系可直接用implements关键字来表示。

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20interface%20CollegePerson%7B%0A%0A%7D%0A%0Apublic%20class%20Professor%20implements%20CollegePerson%7B%0A%0A%7D" wmode="transparent"> 收藏代码

  1. public interface CollegePerson{  

  2.   

  3. }  

  4.   

  5. public class Professor implements CollegePerson{  

  6.   

  7. }  

 接口实现:

 

表示方法一:(在Rose2003 下实现如下,连接线没有箭头,因为方向显而易见)


UML类图与类的关系详解_第12张图片
 

 

表示方法二: 


UML类图与类的关系详解_第13张图片
 

 

 

 

4.3关联(Association

 

表示类与类之间的连接。它使一个类的可见属性和方法被另一个类使用。关联可以是双向或者单向的。双向的关联箭头是可选的,单向的箭头指向遍历或者查询的方向。在Java中,关联使用实例变量来实现。在关联关系中可以使用附加的基数来说明类之间对应的个数。

 

基数

含义

0..1

零个或者一个实例

0..*或者*

没有限制,任意

1

有且只能一个实例

1..*

至少有一个实例

 

常见的基数

 

例:以权限中的用户组、用户角色为例,一个用户角色可以属于一个或者多个用户组,一个用户组则可以包含多个用户角色。如果用户组采用下面的方法来获得用户角色的权限

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20class%20UserGroup%7B%0A%0Aprivate%20UserRole%20uRole%20%3B%0A%0A%20%20%20%20%20%20%20%20%20%20......%0A%0A%7D%0A%0Apublic%20class%20UserRole%7B%0A%0A%7D%20" wmode="transparent"> 收藏代码

  1. public class UserGroup{  

  2.   

  3. private UserRole uRole ;  

  4.   

  5.           ......  

  6.   

  7. }  

  8.   

  9. public class UserRole{  

  10.   

  11. }   

 

 

则表现在图中为:(注意箭头的画法)



 

 


注意:一个关联关系往往是聚合关系或者是合成关系。

 

4.4聚合(Aggregation

 

聚合是关联的一种形式,代表两个类之间的整体/局部关系。聚合暗示着整体在概念上处于比局部更高的一个级别,而关联暗示两个类在概念上位于相同的级别。在Java中,聚合也是使用实例变量来实现的。
关联和聚合的区别纯粹是概念上的,在Java语法上分辨不出来的。聚合还暗示着实例图中不存在回路。换言之,只能是一种单向关系。

 

例:汽车与轮胎的关系可以很好的说问题。

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20class%20Car%7B%0A%0A%20%20%20%20%20%20%20%20%20private%20Tyres%20tyres%3B%0A%7D%0A%0Apublic%20class%20Tyres%7B%0A%0A%7D%20" wmode="transparent"> 收藏代码

  1. public class Car{  

  2.   

  3.          private Tyres tyres;  

  4. }  

  5.   

  6. public class Tyres{  

  7.   

  8. }   

 聚合:

 



 

 

 

4.5合成、组合(Composition

 

合成是聚合的一种特殊形式,暗示局部整体内部的生存期职责。合成关系是不能共享的。所以,虽然局部不一定要随整体的销毁而被销毁,但整体要么负责保持局部的存活状态,要么负责将其销毁。局部不可与其他整体共享。但是,整体可将所有权转交给另一个对象,后者随即将承担生存期职责。

 

       例:人和他的腿就是一个好的例子。

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20class%20Man%7B%0A%0A%20%20%20%20%20%20%20%20%20private%20Legs%20legs%3B%0A%0A%7D%0A%0Apublic%20class%20Legs%7B%0A%0A%7D%20" wmode="transparent"> 收藏代码

  1. public class Man{  

  2.   

  3.          private Legs legs;  

  4.   

  5. }  

  6.   

  7. public class Legs{  

  8.   

  9. }   

 合成:

 



 

 

 

4.6依赖(Dependency

 

依赖也是类与类之间的连接,并且依赖总是单向的。实体之间一个使用关 系暗示一个实体的规范发生变化后,可能影响依赖于它的其他实例。更具体地说,它可转换为对不在实例作用域内的一个类或对象的任何类型的引用。其中包括一个 局部变量,对通过方法调用而获得的一个对象的引用(如下例所示),或者对一个类的静态方法的引用(同时不存在那个类的一个实例)。也可利用依赖来表示包和包之间的关系。由于包中含有类,所以你可根据那些包中的各个类之间的关系,表示出包和包的关系。

 

例:给一个雇员计算薪水的时候,要使用计算器的例子

 

Java代码 <EMBED type=application/x-shockwave-flash pluginspage=http://www.macromedia.com/go/getflashplayer height=15 width=14 src=http://uule.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf allowscriptaccess="always" quality="high" flashvars="clipboard=public%20class%20Employee%7B%0A%0A%20%20%20%20%20%20%20%20%20public%20void%20calcSalary(Calculator%20cSalary)%0A%20%20%20%20%20%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%7D%0A%7D%20" wmode="transparent"> 收藏代码

  1. public class Employee{  

  2.   

  3.          public void calcSalary(Calculator cSalary)  

  4.          {  

  5.   

  6.          }  

  7. }   

 依赖:



 

 

 

你可能感兴趣的:(UML)