一个模型元素的变化影响另一个模型元素,则两个元素之间存在依赖关系。
public class Person
{
void buy(Car car)
{
...
}
}
语义上,所有的关系(类属关系、关联关系和实现关系)都是各种各样的依赖关系,因它们具有很重要的语义,所以在UML中被分离出来成为独立的关系。
// C5.h
#include "C6.h"
class C5
...{
};
// C6.h
#include "C5.h"
class C6
...{
};
指C5可能要用到C6的一些方法,也可以这样说,要完成C5里的所有功能,一定要有C6的方法协助才行。C5依赖于C6的定义,一般是在C5类的头文件中包含了C6的头文件。ROSE对依赖关系不产生属性。
虽然ROSE不生成属性,但在形式上一般是A中的某个方法把B的对象作为参数使用(假设A依赖于B)。如下:
#include "B.h"
class A
...{
void Func(B &b);
}
UML定义了一些依赖关系的原型,以下列出典型的17个原型。原型中用到了源和目标两个概念,源指依赖关系的起始模型元素,目标指依赖关系箭头所指的模型元素。
依赖关系可以分为以下四类:
1) 使用依赖(Usage)表示客户使用提供者提供的服务以实现它的行为,包括:
使用<<use>>--声明使用一个类时需要用到已存在的另一个类。
调用<>--声明一个类调用其他类的操作的方法。
参数<>--声明一个操作和它的参数之间的关系。
发送<>--声明信号发送者和信号接收者之间的关系。
实例化<>--声明用一个类的方法创建了另一个类的实例。
2) 抽象依赖(Abstraction)表示客户与提供者之间用不同的方法表现同一个概念,通常一个概念更抽象,一个概念更具体。包括:
跟踪<>--声明不同模型中的元素之间存在一些连接但不如映射精确。
精化<>--声明具有两个不同语义层次上的元素之间的映射。
派生<>--声明一个实例可以从另一个实例导出。
3) 授权依赖(Permission)表达提供者为客户提供某种权限以访问其内容的情形。包括:
访问<<access>>--允许一个包访问另一个包的内容。
导入<>--允许一个包访问另一个包的内容并为被访问包的组成部分增加别名。
友元<>--允许一个元素访问另一个元素,不管被访问的元素是否具有可见性。
4) 绑定依赖(Binding)较高级的依赖类型,用于绑定模板以创建新的模型元素,包括:
绑定<>--为模板参数指定值,以生成一个新的模型元素。
类属(Generalization)关系描述了一般事物与该事物的特殊种类之间的关系,也即父元素与子元素之间的关系。
如果两个类存在泛化的关系时就使用,例如父和子,动物和老虎,植物和花等。
ROSE生成的代码很简单,如下:
#include "C11.h"
class C12 : public C11
...{
};
上面的图对应的代码如下:
template
class C13
...{
};
关联关系表示两个类之间存在某种语义上的联系。它是一种结构关系,规定了一种事物的对象可以与另一种事物的对象相连。
关联名或关联原型通常是一个动词或动词词组,表示关联关系的类型或目的,帮助理解关联模型。
关联两头的类都以某种角色参与关联。同一个类在不同的关联中,可以扮演不同的角色。阶元表示多少个对象参与该关联。它表示参与关联的对象数目的上下界限制。
C1-C2:指双方都知道对方的存在,都可以调用对方的公共属性和方法。
在GOF的设计模式书上是这样描述的:虽然在分析阶段这种关系是适用的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引用或指针。对象引用本身就是有向的,更适合表达我们所讨论的那种关系。所以这种关系在设计的时候比较少用到,关联一般都是有向的。
使用ROSE 生成的代码是这样的:
class C1
...{
public:
C2* theC2;
};
class C2
...{
public:
C1* theC1;
};
双向关联在代码的表现为双方都拥有对方的一个指针,当然也可以是引用或者是值。
C3->C4:表示相识关系,指C3知道C4,C3可以调用C4的公共属性和方法。没有生命期的依赖。一般是表示为一种引用。
生成代码如下:
class C3
...{
public:
C4* theC4;
};
class C4
...{
};
单向关联的代码就表现为C3有C4的指针,而C4对C3一无所知。
自己引用自己,带着一个自己的引用。
代码如下:
class C14
...{
public:
C14* theC14;
};
就是在自己的内部有着一个自身的引用。
关联关系可导航,表示给顶一端的一个对象,可容易、直接地到达另一端的对象,因为源对象通常含有对目标对象的引用。
单向关联:只在一个方向上导航的关联;
双向关联:在两个方向上都可以导航的关联。关联关系图中,AccountGroup和Account是双向关联,给定一个可以找出另一个;Account和Password是单向关联,给定Account可以发现对应的Password,反之则不然。
限制关联外部对象对于该关联的可见性。关联关系图中,Password为Account私有,它不应被外部对象访问,给定一个AccountGroup对象,可导航到Account对象,但不应该看到Account的Password对象。
限定符是属性或属性列表,通过属性值划分与某个对象通过关联关系连接的对象集,限定符是这个关联的属性。
源对象和限定符的属性值一起可以确定一个目标对象或目标对象集。
接口用来规定类或组件服务的操作集。每个类可实现多个接口。
聚合关系表示类之间的关系是整体与部分的关系,代表了“has-a”(拥有)关系,即作为整体的对象拥有作为部分的对象。整体对象与部分对象不存在一致的生命周期,即整体对象的销毁不一定影响部分对象的存在。
public class 引擎
{
}
public class 轮胎
{
}
public class 汽车
{
protected:引擎 engine;
protected:轮胎 tyre[4];
}
表示C9聚合C10,但是C10可以离开C9而独立存在(独立存在的意思是在某个应用的问题域中这个类的存在有意义。这句话怎么解,请看下面组合里的解释)。
代码如下:
class C9
...{
public:
C10 theC10;
};
class C10
...{
};
组合是聚合的变种,不同的是整体与部分之间具有一致的生命周期。在一个组合关系中,一个对象一次只是一个组合的一部分。“整体”负责“部分”的创建和破坏。(生命周期一致)
class 肢
{
}
class 人
{
protected: 肢 limb[4];
}
class C7
...{
public:
C8 theC8;
};
class C8
...{
};
可以看到,代码和聚合是一样的。具体如何区别,可能就只能用语义来区分了。
关联类是一个既具有关联属性又具有类属性的建模元素。关联关系与关联类图中,Company和Person之间存在雇主/雇员关系,用类Job表示这种关系。关联类用虚线连接到关联关系上。一个关联类只能连到一个关联上,因为关联类本身也是一个关联。
实现关系是分类器之间的语义关系,一个分类器规定合同,另一个实现合同。接口与实现类或组件为典型的实现关系。一个类或组件可以实现多个接口。接口将操作与其实现分离开来。
聚合关系是“has-a”关系,组合关系是“contains-a”关系。
这几种关系都是语义级别的,所以从代码层面并不能完全区分各种关系;但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖
注释是用来将注解或约束与元素或元素集合相连的图形集合。
注释内容可以是文字或图形,或两者的结合。它出现在特定的图上,可以用虚线连接到模型元素上。
参与者代表与系统交互的人、硬件设备或另一个系统。参与者不是软件系统的组成部分,存在于系统的外部。
在UML中,用例规定了系统或部分系统的行为,描述了系统所执行的动作序列集,并为执行者产生一个可供观察的结果。
协作命名了彼此合作完成某个行为的类、接口和其他元素的群体。协作可用来规定用例和操作的实现,为系统体系结构上的重要机制建模。
结构部分用类图详细描述,行为部分用交互作用图详细描述。
协作的行为部分与结构部分必须一致,行为中的对象必须是结构中的类的实例。一个协作可以与多个交互作用相关,每个交互作用描述协作行为的不同方面,且它们保持一致性。
协作不能拥有其它结构元素,被称为系统体系结构的概念性块而不是物理块。
协作名常为系统词汇表的短名词和名词短语,第一个字母大写,如Transaction。
类是面向对象系统中最基本的组成元素。它是分享同样的属性、操作、关系和语义和对象的集合,是现实世界中事物的抽象,具体事物即为类的实例。
类包含3个组成部分。第一个是Java中定义的类名。第二个是属性(attributes)。第三个是该类提供的方法。
属性和操作之前可附加一个可见性修饰符。加号(+)表示具有公共可见性。减号(-)表示私有可见性。#号表示受保护的可见性。省略这些修饰符表示具有package(包)级别的可见性。如果属性或操作具有下划线,表明它是静态的。在操作中,可同时列出它接受的参数,以及返回类型,如下图所示:
可以根据需要隐藏类的属性格或操作格。
一个类可以有0~N个属性,属性描述了为类的所有对象所共有的特性。属性是类的对象所包含饿数据或状态的抽象。特定时刻,属性有特定的值
[可见性]属性名[ :类型][=初始值][{属性字符串}]
[]中的部分可选。
可见性:public / protected / private,+ / # / -
属性字符串:{只读}
[可见性]操作名[(参数表)][ :返回类型][{属性字符串}]
[]中的部分可选。
可见性:public / protected / private,+ / - / #
属性字符串:{只读}
边界类处理系统环境与系统内部之间的通信,为用户或另一个系统(参与者)提供了接口。
边界类用于为系统的接口建模,它代表了系统和系统外的一些实体之间的接口,是系统与外界交换信息的媒介,并将系统与系统环境中的变化隔离开来。
实体类模拟必须被存储的信息和关联行为的类。实体类通常是独立于他们的环境,对于系统环境如何与系统通信是不敏感的。
控制类用来为特定于一个或几个用例的控制行为建模的类。控制类通常是依赖于应用程序的类。
控制对象是控制类的实例,它经常控制其他对象,协调实现用例的规定行为所需要的事件。
同一图中,对象名与对象一一对应。
对象的状态包括对象的所有属性以及每个属性的当前值,它是动态的,状态值是对象在时间和空间的某一点的值。
消息是对象间的通信,传达了了要执行动作的信息,能触发事件。接收到一个消息通常被认为是一个事件。
接口是用来规定类或组件服务的操作的集合。与类不同,接口没有规定任何结构,也没有规定任何实现。
接口是一系列操作的集合,它指定了一个类所提供的服务。它直接对应于Java中的一个接口类型。接口既可用下面的那个图标来表示(上面一个圆圈符号,圆圈符号下面是接口名,中间是直线,直线下面是方法名),也可由附加了<>的一个标准类来表示。通常,根据接口在类图上的样子,就能知道与其他类的关系。
接口可以参与类属关系、关联关系、依赖关系和实现关系。
软件系统中,类模型和对象模型揭示了系统的结构。在UML中,类模型和对象模型分别由类图和对象图表示。
类图描述了类集、接口集、协作以及它们之间的关系。在类图基础上,状态图、协作图等进一步描述系统其它方面的特征。
类图可用来为系统的静态设计视建模。类图组成:
1. 类
2. 接口(操作集合)
3. 协作
4. 依赖、类属、实现或关联关系
车的类图结构为<<abstract>>,表示车是一个抽象类;
它有两个继承类:小汽车和自行车;它们之间的关系为实现关系,使用带空心箭头的虚线表示;
小汽车为与SUV之间也是继承关系,它们之间的关系为泛化关系,使用带空心箭头的实线表示;
小汽车与发动机之间是组合关系,使用带实心箭头的实线表示;
学生与班级之间是聚合关系,使用带空心箭头的实线表示;
学生与身份证之间为关联关系,使用一根实线表示;
学生上学需要用到自行车,与自行车是一种依赖关系,使用带箭头的虚线表示;
public class GooseGroup
{
public Goose goose;
public GooseGroup(Goose goose)
{
this.goose = goose;
}
}
public class Goose
{
public Wings wings;
public Goose()
{
wings=new Wings();
}
}
//双向关联
class B
{
A* pA;
};
class A
{
B* pB;
};
//单向关联
class Person{};
class Friend
{
Person* mpPerson;
};
//自身关联
class C
{
C* pC;
};
在软件开发的不同阶段,类图描述了不同层次的抽象。以需求阶段、设计阶段、实现阶段将类图划分为三个层次:
对象图模拟类图中所含有的类的实例,描述了某一瞬间(具体时刻)对象集及对象间的关系,主要用来为对象结构建模。
对象图可以看作是类图的实例,对象间的连接是类间关联的实例。对象图中通常含有:
(1) 对象(Objects)
(2) 连接(Links)
通常用于为对象结构建模,可用来可视化、规范、构造、并文档化系统中特定实例的存在以及实例间的关系。为对象结构建模时:
包是一个用来将模型单元分组的通用机制。可将一个系统看作一个单一的、高级的包。包用包名相互区别,包名从问题域的词汇表中抽象出的短名词或名词词组。
包可以含有类、接口、组件、节点、协作、用例、图或其他的包。包与其中的元素具有相同的生命周期,一个元素仅被一个包所拥有。
包是一种常规用途的组合机制。UML中的一个包直接对应于Java中的一个包。在Java中,一个包可能含有其他包、类或者同时含有这两者。进行建模时,你通常拥有逻辑性的包,它主要用于对你的模型进行组织。你还会拥有物理性的包,它直接转换成系统中的Java包。每个包的名称对这个包进行了惟一性的标识。
一个包形成一个命名空间。这表示一个包中,不同元素必须有不同的名字。不同包中,元素的命名相互间不受约束。Java.io.File,包之间嵌套。
引入使得一个包中元素可以单向访问另一个包中的元素。包中的公共元素称为包的输出。子包可以看见父包所能看见的所有元素。
包间的类属关系与类间的类属关系类似。
包中元素的可见性是可控制的。
Public / Protected / Private + / - / #