必须掌握的UML

最近看设计模式相关的书籍,对于一个程序员来说,学习设计模式是相当重要的,它能让你设计出高可用和易维护的软件程序,而学习设计模式的一个前提就是能够看懂相关模式的UML图.

UML:即统一建模语言,是当今软件设计的标准图标式设计语言,对于一个软件系统而言:UML具有以下功能:可视化(Visualizing)功能、 说明(Specifying)功能、 建造(Constructing)功能和建文档(Documenting)功能

  通俗的来说:UML就是以一种可视化的方式(图表)来描述软件系统中各结构之间的关联关系 ~

  UML共包括9种图,我们只学习应用场景最多的类图和时序图,如下:

  

类图

  类图(Class Diagram)描述的是类、接口以及它们之间的静态结构和关系的图,类图的最基本元素是类和接口.

  

  如上,就是显示Student的类图,可以看出一个类图共有4层:

  • 类名
  • 属性清单
  • 方法清单
  • 性质清单

  如果一个类存在内部类,那么它的类图会有5层,其中除了类名层不能省略外,其他几层都可以省略.

类名层

  类名层位于类图的第一层,类名如果是正体字,表示类是具体的,Student明显属于具体类,类名如果是斜体,则表明是抽象(abstract)的,如果该类是一个接口,则会有interface关键字进行区分.

属性层

  属性层位于类图的第二层,一个属性可以是public 、protected或private,它们分别使用"+"、“#”、“-”来表示,如上图StudentcourseId属性.

方法层

  方法层位于类图第三层,一个方法也可以是public 、protected或private,表示方式同属性层一致,如果是静态方法 方法名称下面会有一道下划线,需要注意的是构造方法也属于方法层,只不过它是特殊的、无返回值的方法,如上图Student有两个构造方法及两个public的方法say()Study()

性质层

  性质层位于类图第四层,性质层是指那些拥有get()&&set()的属性,即也是使用"+"、“#”、“-”来分别表示public 、protected或private,如上图Studentnameid属性.

  源代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//仅仅为了举例
public class Student {
    private String id;
    private String name;
    public String courseId;

    public Student() {
    }
    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void say() { }
    public boolean study() {return false; }
}

类图中的关系

  在类与类、类和接口、接口和接口之间一般存在以下几种关系:

  • 一般化关系
  • 关联关系
  • 聚合关系
  • 合成关系
  • 依赖关系

  接下来使用一个”王者世界“中的案例来说明这几种关系:

  

一般化(Generalization)关系

  一般化关系描述的是类与类、接口和接口之间的继承关系或类与接口的实现关系,一般化关系由子类指向父类,如上图中的LiuShan(刘禅辅助)LiuBei(刘备)就属于一般化关系,一般化关系使用如下符号表示:

  

关联(Association)关系

  关联关系描述的是类与类之间的联接,它使一个类知道另一个类的属性和方法,关联可以是双向的也可以是单向的,单向关联更加普遍,单向关联使用一个箭头表示,箭头指向的方向表示关联的方向,双向关联可以使用双箭头或者无箭头,关联关系符号的两端可以有一个基数,表明实例之间对应数量的关系,关联关系在Java中一般是通过实例变量来表示的,如“王者世界”中的LuBan(鲁班射手)LiuShan(刘禅辅助)就是关联关系,且一个射手对应一个辅助,所有两端的基数为1:1,关联关系使用如下符号表示:

  

聚合(Aggregation)关系

  聚合关系是关联关系的一种,是一种强的关联关系,聚合关系强调的是部分与整体的关系,如“王者世界”中的LiuShan(刘禅辅助)Cure(治疗)之间的关系就是聚合关系,Cure(治疗)这种辅助召唤师技能就属于辅助的一部分,而LiuShan(刘禅辅助)就属于整体,聚合关系在Java中也是通过实例变量来表示的,所以从语法上无法区分聚合关系和关联关系,如果不确定某种关系是不是聚合关系,那么你可以将其设为关联关系,聚合关系使用如下符号表示:

  

合成关系

  合成关系也是关联关系的一种,它是一种比聚合关系还强的关联关系,它强调部分与整体中的整体需要负责部分的生命周期,合成关系不可以共享,如“王者世界”中的LiuShan(刘禅辅助)和它的身躯MachineBody(机器身躯),合成关系在Java中也是通过实例变量来表示的,所以当无法区分合成关系和以上两种关系时,可以将其设为关联关系,合成关系使用如下符号表示:

  

依赖关系

  依赖关系描述的也是类与类之间的联接,但依赖关系总是单向的,依赖关系表示一个类依赖于另一个类的定义,依赖关系在Java在体现为局部变量、方法参数及静态方法的调用,如“王者世界”中的LuBan(鲁班射手)的发育(grow)总是依赖Equipment(装备),依赖关系使用如下符号表示:

  

  一般而言,每一个类图都应该有类、关联关系、基数~,常用的基数如下:

  

时序图

  时序图指的是按照时间顺序来显示对象之间的执行顺序.

  

  上图描述的是一个查询用户信息的时序图,首先是客户端向UserInfo发起查询用户信息的请求,然后UserInfo调用了ValidateAccess去验证客户端身份,如客户端身份通过,则UserInfo调用自己的selectUser方法查询用户信息,接着UserInfo调用了UserLogger去记录了该次客户端的操作,最后返回用户信息给客户端.

  在时序图中,垂直的虚线叫做生命线,它代表对象的存在时间,每一个箭头都是一次调用,这个箭头从调用者对象连接到接收者对象的生命线上的激活条上,每一个激活条代表调用所持续的时间.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//伪代码,不需要关注细节,关注对应的上面流程即可
void client(){
  //1、客户端请求
   List<User> users=userInfo.selectUser(String username,String password);
}
//UserInfo
public List<User> selectUser(String username,String password){
   List<User> users=null;
  //2、验证客户端身份
   User user=validateAccess.checkUser(String username,String password);
   if(user!=null){
     final String roleId =user.getRole.getRoleId();
     //3、调用自己的selectUser查询用户信息
     users=userInfo.selectUser(roleId); 
     //4、日志记录
     userLogger.saveLogger(User user);
   } 
   //5、返回用户信息给客户端
   return users;
}

总结

  其实在日常工作中,知道以上两种就够了,如果想深入了解UML可以去找一些的相关书籍,最后,谢谢您能看到这里,希望您能给我点个赞,Thank you!

  参考书籍:Java与模式