UML类图最生动的介绍和例子
目的
这篇文章主要是介绍如何使用UML类图,目的是让我们能读懂类图,以及上手使用类图。
为什么要使用UML类图
UML类图是一种统一建模语言,可以精准的描述类中拥有的属性以及方法,以及类与类之间的关系。
它能够非常直观的,通过可视化的方式展示一系列相关类之间的交互关系。
在学习设计模式,或者设计自己的类结构时,大都通过UML类图的形式进行展示。
类图的组成
类图的组成非常很简单,只有类 和 类之间的关系 组成。
类
描述了类内部的内容。其中包括类的属性和类的方法,以及他们的可见性。类之间的关系
描述了类与类之间的交互的方式,包括泛化、实现、依赖、关联、聚合、组合。那么我们先来看一下关于类的部分UML是如何描述的,下面是一个例子
上图描述了一个商品(product)类
首先我们看到这个图的第一部分
该部分描述了这个类的名称,以及它是类型是 类(class)、抽象类(abstract class)还是接口(interface)。
类由C字面表示,抽象类由A表示,接口用I表示。
第二部分描述了类中包含的属性,属性的类型以及可见度
属性可见度+属性名称+冒号+属性类型,这是UML类图描述属性的基本格式。
该例子中,商品(product)类有三个属性,分别是名称(name)、价格(price)和stock(库存)。
名称是String类型的,其余的都是int类型。三个属性全部为私有字段。
可见度
关于可见度有必要说明一下,首先类中的属性和方法每个都可以设置不同的可见度,比如私有的(private)和公共的(public)。在UML类图中的表述方式有直接通过加(+)减(-)表示的,也有通过图标的形式表示的。
因为我们的例子使用的是PlantUML工具实现的,所以把该工具表示可见性的规则放在这里:
下面我们来看类的第三部分
该部分描述类中的方法,相信这部分理解应该问题不大
类图描述方法的格式为:方法可见度+方法名称+方法入参
在例子中,我们提供了三个属性的get方法,以及减库存(reductionStock)方法,它的入参是一个整形,入参名称为数量(num)。它们的可见度均为公共的(public)
那么上述就是关于类图中类的描述
类之间的关系
类之间的关系稍微复杂一些,包含泛化、实现、依赖、关联、聚合、组合。
但实际上这些组合方式我们在代码开发过程中经常使用
我们会成对的介绍它们,并且提供实例,方便理解
如果你对上述关系已经很了解了,可以直接跳到实例阅读,否则建议先了解这些关系的含义
泛化与实现
泛化就是我们常常讲到的继承(extends),是指我们对类或抽象类的继承
实现(implements)比较好理解,是指一个类对接口的实现。
依赖、关联、聚合、组合
这个四种关联关系比较难以区分,我们读一段《Java面向对象编程》对其的定义
概念可能比较多,比较抽象,后面我们会举例子来解释
在这里我们只需要明确,这四种关联关系是层层递进的,耦合度越来越高就可以了。
-
依赖(Dependency)
依赖关系是类与类之间的联接。依赖关系表示一个类依赖于另一个类的定义。依赖关系在Java语言中体现为局域变量、方法的形参,或者对静态方法的调用。 -
关联(Association)
依赖关联关系是类与类之间的联接,它使一个类知道另一个类的属性和方法。关联可以是双向的,也可以是单向的。在Java语言中,关联关系一般使用成员变量来实现。 -
聚合(Aggregation)
聚合关系是关联关系的一种,是强的关联关系。聚合是整体和个体之间的关系。例如,汽车类与引擎类、轮胎类,以及其它的零件类之间的关系便整体和个体的关系。与关联关系一样,聚合关系也是通过实例变量实现的。但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在不平等层次上的,一个代表整体,另一个代表部分。 -
组合(Composition)
组合关系是关联关系的一种,是比聚合关系强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分对象的生命周期,组合关系是不能共享的。代表整体的对象需要负责保持部分对象和存活,在一些情况下将负责代表部分的对象湮灭掉。代表整体的对象可以将代表部分的对象传递给另一个对象,由后者负责此对象的生命周期。换言之,代表部分的对象在每一个时刻只能与一个对象发生组合关系,由后者排他地负责生命周期。部分和整体的生命周期一样。
——摘自《Java面向对象编程》,作者:孙卫琴
类关系的实例
OK那么我们接下来逐个解释
1. 泛化
泛化符号是以三角箭头以及实线组成
该例子中,狗(dog)类继承了动物类(animal)
实现代码
class main{class animal {public void move(){print("move")}}class dog extends animal {public void bark(){print("wangwangwagn")}} }2. 实现
泛化符号是以三角箭头以及虚线组成
该例子中,汽车类(car)实现了运输接口(Transport)
实现代码
class Main{interface Transport{void deliver();}class Car implements Transport{public void deliver(){print("deliver to destination")}} }3. 依赖
依赖关系表示一个类依赖于另一个类的定义,即一个类的实现需要另一个类的协助。依赖关系通常是局部的,在程序中的体现往往是A类的某个方法需要传入一个B类,或者A类在某个方法中创建了B类局部变量。
依赖是通过箭头+虚线表示的
在该例子中,我们有一个人(People)类,它有两个方法打猎(hunting)和吃饭(eat)。
其中打猎方法调用时需要传入枪(Gun)类,吃饭方法调用时需要传入食物(Food)类。
此时,人(People)类就是的实现就依赖于枪(Gun)和食物(Food)类。
代码实现
class Main{class Gun{public void get(){print("这是一把枪!"); }}class Food{public void get(){print("这是一份食物!"); }}class People{public void hunting(Gun gun){gun.get();print("获取枪支,开始打猎!");}public void eat(Food food){food.get();print("获取食物,开始吃饭!");}}}4. 关联
关联关系比依赖关系更近一步,它使一个类知道另一个类的属性和方法。
在代码的体现上通常是作为类中的成员变量存在。
关联是通过箭头+实线表示的
在该例子中,我们拥有警察类(Police)和枪(Gun)类
警察类通过成员变量gun与枪类进行关联
警察在调用waring()和shooting()方法时使用了gun。
区别
这里需要注意的是与上一个例子的区别
这两个例子中都存在枪(Gun)类,但不同的是警察在是一直要佩戴枪支的
而普通人只有在打猎场景时(对应调用hunting()方法时)才需要枪
普通人与枪的关系时依赖关系
而警察与枪的关系时关联
代码实现
class Main{class Gun{public void show(){print("展示枪支")}public void shooting(){print("发射子弹!")}}class Police{private Gun gun;public setGun(gun){this.gun = gun;}//警察通过持枪警告罪犯public void waring(){gun.show()print("不许动!")}//警察使用枪支进行射击public void shooting(){gun.shooting()}}}5. 聚合
聚合关系是关联关系的一种,是强的关联关系。聚合强调的是对象之前整体与部分的依赖关系。
与关联关系一样,聚合关系也是通过实例变量实现的。但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在不平等层次上的,一个代表整体,另一个代表部分
聚合是通过空心菱形+实线表示的
该例子中,汽车(Car)类与引擎(Engine)类属于聚合的关系
其中Engine属于Car的一部分,双方的关系不是对等的关系
代码实现
class Main{public class Engine{public void on(){print("引擎启动");}}public class Car{Engine engine;void setEngine(Engine engine){this.engine = engine;}public void show(){engine.show();pring("开车去兜风");}}void Main(){Car car = new Car();car.setEngine(new Engine());car.show();}}6. 组合
组合关系又是聚合关系的加强
其中组合关系强调的是整体对象负责管理部分对象的生命周期
而且在整个过程中,代表部分的对象应只属于一个整体对象。
组合是通过实心菱形+实线表示的
该例子中,学校(School)类与班级(Classes)类属于组合的关系
学校构建了所有的班级集合,并管理它们的生命周期。
而班级只属于某所学校,在整个生命周期中,除非有必要(在本实例中没有这个必要),否则学校类甚至可以不暴露任何有关班级的实体。
也就是说,学校类可以拥有对班级类完整的控制权。
代码实现
class Main{public class School{private Stirng name;private List<Classes> classesList;public School(int sumClasses){classesList = ArrayList<>();for(int i = 0 ; i < sumClasses ; i ++){classesList.add(new Classes(sumClasses+"班级"));}}public void giveLessons(){print("上课啦!");for(Classes Classes : classesList){Classes.giveLessons();}}}public class Classes{private Stirng name;public Classes (String name){this.name = name;}public void giveLessons(){print(name+"班上课啦!");}}void Main(){new School().giveLessons();}}画图软件
简单的介绍一款画图软件,叫PlantUML
这个软件的优点是通过简单的代码就能生成UML图,而且支持中文,官网有很多详细的使用方法和例子
对比较熟悉代码的朋友们来说,这个画图软件还是比较好用的(其实都不应该叫画图软件了lol)
但是如果是对代码不是很理解,或者不能很方便的用代码作为生产力的同学
还是建议根据自己的系统平台找一找别的画图软件,这里就不展开了
结语
OK那么关于UML类图的介绍就到这里了。这篇文章断断续续写了蛮久,主要是因为个人原因,一直觉得有些例子没有很好的诠释这些关系中的区别,但是一耽搁就几个月没再动笔了。
这篇文章的目的主要是想通过比较简单的语言加上例子,让大家对这些关系有一个比较清楚的认识。
如果觉得文章中有错误的地方请及时指正,谢谢!
总结
以上是生活随笔为你收集整理的UML类图最生动的介绍和例子的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Qt程序移植
- 下一篇: pc 装MAC 资料