UML 相关知识
本单元中,我们统一使用starUML软件绘图
类图
泛化和实现
描述类与类,类与接口,接口与接口之间两种“纵向关系”的是:
泛化(Generalization)和实现(Realization)也即“is a”
- 泛化(即继承)用:空心三角形+实线
- 实现(类实现接口)用:空心三角形+虚线
依赖,关联,聚合,组合
依赖(Dependency)
依赖是一种弱关联关系,也即“use a”关系。如果对象A用到对象B,但是和B的关系不是太明显的时候,就可以把这种关系看作是依赖关系。
依赖使用虚线箭头表示,箭头的终点表示被依赖的对象:
如果对象A依赖于对象B,则 A “use a” B。具体的,在Java代码中,有以下四种表现形式:
-
B的实例为A的构造函数或方法中的局部变量
-
A调用了B的静态方法
-
B的实例为A的方法中的参数
-
B的实例为A方法中的返回值
关联(Association)
关联是指对象和对象之间的连接,它使一个对象知道另一个对象的属性和方法。
关联关系有单向关联和双向关联。如果两个对象都知道(即可以调用)对方的公共属性和操作,那么二者就是双向关联。如果只有一个对象知道(即可以调用)另一个对象的公共属性和操作,那么就是单向关联。大多数关联都是单向关联,单向关联关系更容易建立和维护,有助于寻找可重用的类。
在Java中,关联关系的代码表现形式为一个对象含有另一个对象的引用。
双向关联关系用带双箭头的实线或者无箭头的实线表示,单向关联用实线箭头表示,箭头指向被关联的对象。
聚合(Aggregation)
聚合是关联关系的一种特例,它体现的是整体与部分的拥有关系,即 “has a” 的关系。此时整体与部分之间是可分离的,它们可以具有各自的生命周期。整体对象可以包含部分对象,但部分对象的生命周期不依赖于整体对象。
聚合关系用空心菱形箭头表示,其中菱形箭头的一方表示整体。
那么聚合与关联究竟有何区别呢?
在代码上,聚合关系与关联关系一样,都是通过成员变量实现的,但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在不平等层次上的,一个代表整体,另一个代表部分。
在这里,我们以师父和徒弟为例,说明关联关系与聚合关系的区别。
譬如现在有师父类徒弟类
我们假设师父可以自行决定收哪些徒弟,徒弟也可以自由选择自己的师父,师父可以劝离徒弟,徒弟也可以自行决定解除师徒关系,那么此时师父与徒弟就是平等的关联关系。
但如果我们假设徒弟选择师父后,徒弟无权自行解除师徒关系,只能被师父劝离,但注意劝离后,徒弟仍能再次选择师父(即不影响生命周期)。此时我们就可以认为二者的关系为聚合关系。
组合(Composition)
组合也是关联关系的一种特例,它同样体现整体与部分间的包含关系,即“contains a”的关系。但此时整体与部分是不可分的,部分也不能给其它整体共享,作为整体的对象负责部分的对象的生命周期。这种关系比聚合更强,也称为强聚合。如果A组合B,则A需要知道B的生存周期,即可能A负责生成或者释放B,或者A通过某种途径知道B的生成和释放。
组合关系用实心菱形箭头表示,其中菱形箭头的一方表示整体。
那么组合与聚合究竟有何区别呢?
区别在于组合关系中,整体需要负责部分的生命周期,在代码中,通常表现为构造函数中的初始化,或解除关系时的析构与销毁。
我们仍以上面的师父-徒弟场景为例:
我们假设师父劝离徒弟后,徒弟不得再次寻找其它师父,在程序中,表现为徒弟对象被永久销毁,那么我们就可以说,此时二者的关系为组合关系。
小结一下类之间的四种横向关系,就关系的强弱顺序而言
依赖<关联<聚合<组合
其中关联,聚合,组合在语法上无法区分,必须考察语义与具体的逻辑才能区分。
状态图
起始状态,中间状态,结束状态
状态机的起始状态用黑色实心圆点表示,起始状态只能有出度,不能有入度。
状态机的中间状态,用圆角矩形表示。
状态机的结束状态,用带外圆的黑色实心圆点表示。
状态转移
状态机的状态转换,在转换前状态指向转换后状态的黑实线上表示:
只有当响应事件发生的时候才有可能进行状态转换。事件标记是转移的诱因,可以是一个信号,事件、条件变化(a change in some condition)和时间表达式。在我们的课程中应该只需要考虑事件(函数调用), 所以 UmlEvent 通常是方法。
生命一个实际的状态转换事件,通常由四个部分组成:
- 名称:如这里的 Open ,方便我们识别这里的动作是什么
- 事件标记:如这里的 open(key) , 表示状态转移的发生条件,并不是所有的事件都能在任何状态转移
- 守护条件:如这里的 key.id==locker.getId() 表示判定是否状态转移发生的条件,显然当钥匙和门不对应的时候不能开锁;
- 结果:如这里的 locker.unlock(key) ,只有当事件标记发生且守护条件成立的情况下才能执行后续的结果操作。
顺序图
生命线
顺序图中的生命线,表示对象的生存时间,用矩形下连虚线表示:
- name 的命名方法有以下几条规则:
[对象名][:类名]
具体有以下几种方式:
-
对象名
-
类名:对象名
-
类名
- 当使用下划线时,意味着顺序图中的生命线代表一个类的特定实体。
- 每个生命线都关系到一个实体。
消息
顺序图中的消息,用黑实线和箭头表示:
对象之间的交互是通过相互发消息来实现的。一个对象可以请求 (要求)另一个对象做某件事件。消息从源对象指向目标对象。消息一旦发送便从源对象转移到目标对象。
消息也分主要分成六类:
同步消息
消息的发送者把进程控制传递给消息的接收者,然后暂停活动,等待消息接收者的回应消息。
异步消息
消息的发送者将消息发送给消息的接受者后,不用等待回应的消息,即可开始另一个活动。
返回消息
返回消息和同步消息结合使用,因为异步消息不进行等待,所以不需要知道返回值。
创建消息
创建消息用来创建一个实例,可以测试出,若指向一个声明线的中部,StarUML 会自动将目标生命线 移动到创建消息的地方开始,其上方不存在。
**摧毁消息:**特别注明 <>
摧毁消息用来摧毁一个实例,生命线上会出现一个 X 表示结束。
Lost and Found Message
这类消息的特点是它可能没有发送者或者接收者
Lost and Found Message 实际应为两种:Lost Message 和 Found Message。
有时候我们不需要关心发送者是哪个对象,此时称该消息为 Found Message,其 source 值为 发送者 UmlEndpoint 。
类似地,有时候我们不需要关心接收者是哪个对象,此时称该消息为 Lost Message,其 target 值为接收者 UmlEndpoint