-描述设计模式的时候会经常用到UML类图来描述类之间的静态结构。此篇的用意仅仅在于让各位看官能够看懂UML类图,并且弄清楚UML类图中的几种关系。
-在之后的设计模式学习过程中仅此两点足矣,更高深的不在此篇讨论范围内。
JohnConnor设计模式笔记系列 目录
JohnConnor设计模式笔记(一) 学习设计模式之前你必须掌握的-看懂UML类图
JohnConnor设计模式笔记(二) 程序世界里的复印机-原型模式与浅复制/深复制
未完待续......
UML类图是UML(unified modeling language,标准建模语言)五种图示法中静态图的一种-用来描述系统中类的静态结构,不仅定义系统中的类,表示类之间的联系如关联、依赖、聚合等,也包括类的内部结构(类的属性和操作)。类图描述的是一种静态关系,在系统的整个生命周期都是有效的。
如果诸位看官们有拜读过一些关于设计模式的动动,就一定有接触UML类图,可以说学习类图是设计模式之旅的起点,下面我们来看一个示例。
一,类的表示
想必电影终结者是深入人心,既然我的英文名与主角同名,那就来个终结者T-800(阿诺肌肉辛格)把。
通常UML类图中的一个节点就是一个类或者接口。从这个T-800的类我们可以看出,
- 类是由一个三层的矩形组成的:顶部显示类名,中部显示特性(属性或字段等),底部显示操作(方法或行为)
- 特性的格式是: 可见性修饰符 属性名:类型 <=默认值>。T-800的特性有型号,目标等。
- 操作的格式是: 可见性修饰符 操作名(<参数列表>):返回类型。操作参数的格式则是<in/out>参数名:类型。in/out来指示参数是输入还是输出类型。T-800的操作是重启。
- 在UML类图中可见性'+'表示public,'-'表示private,'#'则表示protected。
除了上述例子中可见的UML类图的规则之外,这里再补充几点:
- 如果这个类是抽象类,那么类名就必须使用斜体字。
- 如果在一个类图中我们只想显示高层细节,那下面的两个区域的信息不是必要的。
- 操作的参数in/out,除非使用早期的编程语言,这个in/out指示器会有所帮助,一般情况下省略。
二,接口的表示
接口的表示有两种方式:
- 矩形表示与类的表示相似,不过需要在接口名称上方标注<<interface>>,并且接口只有两个部份,接口名和方法。
- 棒棒糖表示法,在棒棒糖的名字就是接口的名字,其方法写在负责实现它的类的操作部份。这里省略了T-800的特性和操作细节。
三,UML类图中的关系
1.泛化关系(Generalization):使用带空心三角形的实线表示。
不管是基本款T-800还是液体金属T-1000,还是最新款的T-X,它们都属于终结者系列机器人:
泛化关系相当于面向对象中的继承关系。类T-800,T-1000,T-X都继承自抽象类(注意类名是斜体)终结者类,则称终结者类是前三者的一个泛化。
在UML中对泛化关系有三个要求,
- 子类需要继承父类所有的特性和操作,如上述的三个子类都继承了父类的型号和目标字段。
- 子类中除了与父类一致的信息外,还应包括额外的信息。比如新的操作:T-800可以重启(重新设定目标),T-1000可以液化,T-X能控制其他机械。
- 可以使用父类的地方,也可以使用子类。
2.实现关系(Emlpementation):使用带空心三角形的虚线表示。
在上面的例子中T-800实现了攻击接口,就引申出了实现关系。
在UML中接口就是一个操作的集合。
3.依赖关系(Dependency):使用带箭头的虚线表示。
机器人们依赖于内部的指令来行动。也可以通过指令来重启T-800来执行其他任务。
依赖是一种最弱的横向关系。假设A类的变化引起了B类的变化,则称B依赖于A。表现在代码上依赖关系一般有如下三种情况:
- A类是B类中(某个方法)的局部变量。
- A类是B类中某个方法的参数。
- A类向B类发送消息,从而影响B类变化。
4.关联关系(Association):使用实线表示(可带箭头)。
从这开始大家可能就会混掉了。不过没关系,最后会辨析这几种关系。如果看官们熟悉魔兽世界,两个一起打22竞技场的好基友就是1对1的关联关系。
如果甲是治疗,那这个实线就可以带箭头指向乙。因为只需要前者奶好后者,后者只管砍敌人(当然这是很低端的做法吼吼)。
关联往往是相互的。关联的两个对象彼此间没有任何强制性的约束,可以随时解除关系或是进行关联,生命期问题上没有任何约定。
被关联的对象还可以再被别的对象关联,所以关联是可以共享的。
数字表示了关联两者之前的多重性,一般有“*”表示不限,“1”表示有且只有一个,“0...”表示0个或多个,“0,1”表示0个或1个,“m...n”表示m~n个,“m...*”表示至少m个。
5.聚合关系(Aggregation):使用带空心棱形的实线表示。
聚合关系表示一种弱的整体对部份的拥有关系。主要体现在两者的生命周期不同,部份可以脱离整体存在。
被聚合的对象还可以再被别的对象关联,所以被聚合对象是可以共享的。
比如魔兽中的天灾军团,天灾们受巫妖王的思想控制,现在小阿被脚男们推倒干掉了天灾军团完蛋了,
旗下的死亡骑士们就追随黑风骑士团效忠联盟或者部落,并不意味着他们也就OVER了。
其实聚合也是关联关系的一个特例。但更紧密,你会跟女朋友亲密的分享一切,但不会给一个来串门的朋友配自己家的钥匙把。
6.组合关系(Composition):使用带实心棱形的实线表示。
组合关系表示一种强的整体对部份的拥有关系。
在终结者系列电影中,天网是一套拥有了自己意识军事防御体系的控制程序,控制着麾下的所有机械军团。
天网系统被摧毁,机械军团就成了一堆废铜烂铁了。(刚才跑题到魔兽世界去了,呃....)
主体控制着部份的创建和销毁或转移,部份的生命周期由主体掌握。这就是组合关系。其实也是关联关系的一种特例。
四,几种关系的联系与区别
泛化与实现是两个纵向关系,这两者没什么异议很好区别。
依赖,关联,聚合,组合这四个横向关系,由弱到强,区分倒是比较麻烦。
依赖(...use a...) 与其他三者最大的区别在于仅仅是使用,并不持有其依赖对象的引用。代码的表现就是并不是类的成员之一,而是其方法的参数或局部变量。
聚合(... owns a ...),组合(... is a part of ...),都是关联(...has a...)的特例。
但关联更倾向与两个独立平等的事物之前的关系,比如好基友,或者好朋友,然而聚合和组合倾向于整体和部份的关系。
聚合和组合的区别,只是在于整体对部份生命周期的把握程度。
聚合就像是电脑坏了的话,硬盘之类的东西是可以继续用的。组合就像是二极管收音机坏了,那就整个报废了(对于一般人来说...高手不要吐槽说你会修...)
----------------------------------------------偶是分割线---------------------------------------------------
End:补充一下类图中的注释Like this:
最近在学习设计模式,可能的话后面会推出一个系列。我写的动动一般都是面对跟我一样的初学者。希望大家到时候捧场吼吼!
以上的图都是使用MS Visio画出来的,如果大家感兴趣我也可以写一篇关于使用Visio画UML类图的文章^_^。