(三) UML-类关系
前言
在上一篇文章中,我们介绍了类的相关要素用 UML 表示的方法,对于抽象类和抽象方法虽然提到了其使用
斜体
表示,但并没有展示对应的 UML图,本文将使用 UML 来展示类(包括抽象类)之间的关系。
继承和引用——是可以并列存在的
UML 类图是从类与类的
耦合度
上进行描述的,从代码层面看一种是继承
(或者实现
,涉及到接口,本文暂不论述),就是具备了子类父类的概念;一种是类引用,就是类一中用到了类二。
引用的形式有很多种,比如声明实例化、使用其他类的静态方法、本类方法入返参用到其他类、抛出异常用到其他类等。
继承其实也是一种类引用,不过子类既可以继承超类,与此同时也可以在其类内部再次引用到超类,所以这里需要强调一下,继承和引用是可以同时出现在同一个类关系
中的。
打通 UML 表示类关系的任督二脉——同一段代码,不同的梦想
再往下走就要涉及一些枯燥的概念了,尽管笔者希望尽力将其简化,但是发现就细节讲细节像是进入了思维迷宫,所以整理出本段单独阐述一下。
在上面我们已经提到 UML 类图是从类的耦合度上进行描述的,那么耦合度是谁决定的?比如类一需要实例化类二,类一调类二的静态方法。再比如,公司和部门的关系与自助餐和饮料的关系是一样的吗?
我猜你已经想到了一些什么,UML 在表示类关系的时候对现实世界进行了一定的关联,或者说,同一种类型的代码,由于实际含义的不同可以采取不同的 UML 类图进行描述。
总结:UML 在表述类关系的时候分为了两种情况:
1、继承关系与引用关系,二者可以并列存在
2、引用关系分为实例化引用和非实例化引用
3、在实例化引用中,比如部门脱离公司不可以单独存在,因为没有意义,但是饮料没有自助餐依旧是OK的,一个教师可以有多个学生,一个学生也可以有多个老师,所以你可以看到,在表示实例化引用的关系中,各类的耦合度是不同的,但是很有可能是同一个样式的 Java 代码:类一中声明了类二。
所以使用 UML 描述类关系的时候一定是关注代码的现实意义的。否则你一定会在选择上不知所措。希望你看懂了,或者在看完下面完整的内容后再来阅读本段内容。
概念上的区分
UML 中与类相关的概念有
泛化
、实现
、组合
、聚合
、关联
、和依赖
。
从关联的紧密程度来说 【泛化=实现】>【组合>聚合>关联>依赖】,然后再次强调左边【】和右边【】可以同时存在于同一个UML类关系中泛化
是子类与超类的关系,即继承实现
是类与接口的关系,本文暂不论述组合
和聚合
,都是单向引用关系,从代码层级看没有区别,但是从实际含义看是有区别的组合
是一种强引用关系,且被组合类从含义上来说单独存在没有意义,比如公司类和部门类,部门脱离公司没有存在的意义聚合
是一种强引用关系,被聚合的类单独存在具有意义,比如自助餐类和饮料类、啤酒类、羊肉卷类等,没有自助餐,饮料照样可以存在关联
,类与类不存在继承关系,但是存在对象实例化引用,比如类一作为类二的一个属性,关联是可以双向的,比如商店类和顾客类依赖
是一种最弱的引用关系,比如方法的出入参、抛出的异常、对其他类的静态方法的引用
图形上的区分
连线一般意味着二者的实例存在关联关系,实线意味着
被引用类
需要引用类
来实例化,虚线意味着被引用类的实例化工作不是引用类的职责,比如方法的出入参涉及被引用类
、异常抛出为被引用类
、调用被引用类的静态方法
从图形上看基本上有实线加三角形
、虚线加三角形
、实线加实心菱形
、实线加空心菱形
、实线加箭头
、虚线加箭头
实线加三角形
,用于表示子类继承超类,子类-实线-三角形-超类,三角形指向超类虚线加三角形
,用于类实现接口,本文暂不论述实线加箭头
,表示引用类需要引用并负责被引用类的实例化工作虚线加箭头
,表示被引用类的实例化工作不是本类或者本类必须做的实线加实心菱形
,这个图形有时候会加上一个开口箭头,可以认为是实线加箭头
的扩展,实现加箭头指示表示了对象引用,而实心菱形+实线+箭头则表示被引用类是引用类的组成部分,实心菱形表示被引用类必须依附于引用类存在。实心菱形和引用类直接连接。实线加空心菱形
,和实线加实心菱形类似,也可以和开口箭头使用,不同之处在于空心菱形连接的类所以来的被引用类是可以单独存在的,比如自助餐类和饮料类。
类和 UML 概念与图形的联系
泛化——实线加三角形
引用类-实线-指向被引用类的三角形-被引用类
//超类-抽象类
public abstract class AbstractMap < K,V>;
//超类中的抽象方法
public abstract Set< Entry< K,V>> entrySet();
//子类继承父类
public class HashMap < K,V> extends AbstractMap < K,V>;
//子类实现的抽象方法
public Set<Map.Entry< K,V>> entrySet() {
return entrySet0();}
实现——虚线加三角形
类实现接口就是虚线加三角形,本文暂不叙述涉及到接口相关的内容
组合——实线加实心菱形
引用类-实心菱形-实线-[指向被引用类的箭头]-被引用类
这里举例,公司类与部门类,公司类引用部门类,部门组成公司,部门必须依赖公司存在
//公司类
class Company{
private Department department;
//内容略...
}
//部门类
class Department{
//内容略...
}
聚合——实线加空心菱形
引用类-空心菱形-实线-[指向被引用类的箭头]-被引用类
这里 自助餐引用饮料,饮料是自助餐的一部分,饮料可以单独存在
//自助餐
class Buffet{
private Drink drink;
//内容略...
}
//饮料
class Drink{
//内容略...
}
关联——实线加箭头
引用类-实线-指向被引用类的箭头-被引用类
这里 学生和课程,由于存在一对多的情况,这里引入了一个新的符号,0..,表示一个学生对应0或者多个课程, 也可以换为具体的数字。
//学生
class Student{
private List<Course> courseList;
//内容略
}
//课程
class Course{
//内容略
}
依赖——虚线加箭头
引用类-虚线-指向被引用类的箭头-被引用类
上文已经提到,依赖的场景很多,比如引用类的方法出入参用到被引用类,引用类抛出异常用到被引用类,引用类通过静态方法引用被引用类。
pubic class TestClass{
public void test() throws Exception{
//内容略
}
}
public class TestClass{
public void test(Course course) throws Exception{
//内容略
}
}
public class StaticClass{
public static void testStatic(){
//内容略
}
}
public class TestClass{
public void test(Course course) throws Exception{
//引用静态方法
StaticClass.testStatic();
//内容略
}
}
对于双向引用与n(n>=0)对多的情况
在上面的图形中我们用到了
箭头
,n..*
来表述引用关系,如果是双向引用可以不使用箭头。
其他一对多 1..*,一对一 1..1,这种就可以*使用了。
参考链接
网络让知识*流动
[1].《Java 设计模式 (第2版)》
[2].https://blog.csdn.net/wglla/article/details/52225571
[3].http://www.uml.org.cn/oobject/201609062.asp
[4].https://blog.csdn.net/iamherego/article/details/44802855
上一篇: python模块之re正则表达式详解
下一篇: 利用python画一颗心的方法示例