前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UML系列(2):快速读懂结构间的关系

UML系列(2):快速读懂结构间的关系

作者头像
Homqyy
发布2023-03-06 13:21:22
3190
发布2023-03-06 13:21:22
举报
文章被收录于专栏:知行合一知行合一

前言

研发们或者技术经理们应当有体验过这种感觉,那就是“感觉我讲得挺好的,但是对方就是没能理解”。其实出现这种问题的原因往往不是因为对方理解能力差,或则自身表达不够,而是因为双方有较大的“知识落差”。那么“知识落差”到底是什么意思呢?其实很简单,就是双方各自的“知识链”不同,因此对相同事物的看法和表述不同,从而导致了理解的误差,形成了当前难以沟通的局面。但是“知识链”是几乎无法完全相同的,毕竟人的经历和学识都各不相同。那该如何解决这样的问题呢?最好的方法就是在沟通的内容范围内,用相互理解的语言进行沟通,即构建受限的“知识链”。这样哪怕彼此的三观不同,也能在工作内容中进行有效的沟通。而UML就是承接了这种责任的建模语言。

在阅读此篇前,应当先阅读《UML系列(1):认识UML踏入设计之路》以对UML有一个基础的认识。同时应当具备一定的面向对象编程(OOP)的思想,这样才能真正的发挥UML的用处。

我们知道,在现实世界中人、事物间的关系是非常重要的,有了关系才有了因果,它们在一个相互的作用下共同组成了我们这个纷杂的世界。而在程序设计中,各系统、组件、对象间的关系也是极其重要的,因此学会正确的表达其关系就成为了沟通或设计的首要任务

在UML中,有如下几种常见关系:

  • 关联(association)
  • 继承(inheritance)/泛化(generalization)
  • 依赖(dependency)
  • 实现(realization)
  • 聚合(aggregation)
  • 组成(composite)

在陈述上述关系之前,我们需要知道“关系之间是存在约束的,同时也能用构造型来创造新的关系。”


关联

当类之间在概念上有连接关系时,类之间的连接叫做关联(由于关联表达的是连接,因此还能用关联图去表达空间的位置关系)。比如在篮球游戏中会有如下关系:

关联示例图1

这样的一幅图表达的内容是:“队员(Player)在球队(Team)打球。且队员是雇员(Employee),球队是雇主(Employer)。一个球队可以有5~10个队员”。当然,“队员”和“球队”代表的程序中的两个类。你看懂了吗?没看懂的话没关系,接着对上图进行分解解释:

  • 先陈述第一句话“队员在球队打球”,这句话表达出了队员和球队之间的联系。那么在UML中可以如此表达,开始可以先说明“队员”和“球队”之间存在关联,这里用一条直线表示。从句子中不然发现“队员“是关系的发起者,因此在关联线的中间用箭头表示这样的关系,同时在方向后方添加描述“Plays on”来对该方向做进一步解释,最终就表达出了我们要的意思了,如下图所示:

队员在球队打球示例图

  • 接着表达的是第二句“队员是雇员,球队是雇主”,这句话表达出了队员和球队各自的角色。在UML中可以如下表达,在接近类的关联线的地方上表明每个类的角色,于是形成了下图:

队员是雇员,球队是雇主示例图

  • 最后表达最后一句话“一个球队可以有5~10个队员”,这句话表达出了队员和球队的数量关系。在UML中称为多重性(multiplicity),表示方法是在参与关联的类附近的关联线上注明多重性的数值,于是形成了下图:

一个球队可以有5~10个队员示例图

有时候关联关系从不同的角度来看是不同的,比如上面描述了“队员”是雇员、球队是“雇主”,因此还可以表达成“球队雇佣队员”,这句话的发起者是“球队”,因此我们在关联线中间添加箭头,同时用“Employs”进行描述,其UML表示如下图所示:

球队雇佣队员示例图

有时关系可能不是1对1的,可能是n对1的,比如:“一个球队有前锋,中锋和后卫”。这时可以用UML这么表达多个类关联1个类:

一个球队有前锋,中锋和后卫示例图

约束

开始有提到过“关系之间是存在约束的”,因此关联也有这样的表达。比如:“银行柜台服务员(Bank Teller)为顾客(Customer)服务(serve),但是服务的顺序要按照顾客排队的次序进行”,此时UML可以如下表示:

关联约束示例图

  • UML用花括号来表示约束,在受约束的类附近加一个花括号扩起来的“ordered”来表示约束顾客的次序。

约束关系还有一种是“Or(或)”,比如:“大学生(HighSchoolStudent)选修课可以选择诗歌(Poetry)或商务(Commercial)”,UML可以如下表示:

约束Or示例图

  • 在两个关联线之间连一条虚线,并在虚线之上标识”{or}“来表示这种约束。

关联类

和类一样,关联也可以有自己的属性和操作,这样的关联称为关联类(association class)。比如:“队员”和“球队”之间的关系是通过“合约(Contract)”关联起来的,而合约的签订由“总经理(GeneralManager)”商定(Negotiates),因此我们可以用UML表达这样的关联,如下所示:

关联类示例图

  • 关联类也是一个类,因此“合约”的表达方式跟“队员”或“球队”是一样的,只是需要通过一条虚线把关联类和对应的关联线连接起来,以表示该类是关联线的类,即关联类。

前面我们说过,关联类也是一个类,因此正如对象是类的实例一样,关联也有自己的实例,关联类的实例我们称之为

在“UML系列(1):认识UML踏入设计之路”中有提到过实例(对象)的表达方式:

  • 类名前提供对象名称,并用冒号分隔。且对象名称的首个单词的首字母是小写的
  • 对象名和类名有下划线

链的表达方式也是如此,需要添加下划线,同时链是专门用来关联实例的,而不是类。比如:“科比(kobeBeanBryant)”效力于“湖人队(losAngelesLakers)”:

链示例图

  • 这里由于工具的原因,没能将“Playes on”添加下划线,因此在空格的地方追加下划线以做表示。

多重性

前文在讲述“队员”与“球队”关系的时候提到了多重性,这里讲一下其表达方式:

  • *表示许多,即>=1的意思。
  • ..表示连续或,即1..10表达的是1到10中的任一数。
  • ,表示序列或,即1,5,7表达的是1或5或7。

限定关联

当关联的多重性是1对多时,就产生了一个问题:查找问题。比如我们想在一个“房间预订列表”中查找其中的一条“预定信息”时,需要有个具体的查找条件,该条件应是“预定信息”的某个属性。我们将表达这种查找(限定)关系称为限定符(qualifier):

房间预订列表与预订信息的关系示例图

如上所示,“房间预订列表”与“预订信息”是1对n的关系,通常一个“预订信息”会对应唯一的一个“订单号(orderNumber)”用于“房间预订列表”查询条件,其UML表示如下:

限定符示例图

  • 如上所示,虽然“房间预订列表”与“预订信息”是1对n的关系,但是“订单号”与“预订信息”是1对1的关系。

自身关联

有时候一个类可能与它自身发生关联,这样的关联被称为自身关联(reflexive association)。当一个类的示例可以充当多种角色时,自身关联就可能发生。

比如,一位“车上的人(CarOccupant)”既可能是一位“司机(driver)”,也可能是一位“乘客(passenger)”,那么一个司机可以搭载0到4位乘客,因此其UML表达为:

自身关联示例图


继承和泛化

继承和泛化是OOP的用语,这里不对这两术语进行解释,感兴趣的可以自行搜索。继承是“is a”表达,在各种OOP语言都会提到此概念,比如:“哺乳动物(Mammal)”是一种“动物(Animal)”,“马(Horse)”是一种“哺乳动物”:

继承示例图

  • 实线连接父类和子类,且用空心箭头指向父类。

了解对象的知道,除了父类和子类外还有基类(base class)或根类(root class)、叶类(leaf class)、抽象类(abstract class)的称呼。这些称呼中抽象类是比较特殊的,它表示一个类是不提供实例对象的,在UML也有特定表达方式,就是“将类名用斜体书写”:

基类示例图

如上图所示,我们重新回到队员的关系中,上图表明:

  • “队员”由“后卫”、“前锋”、“中锋”继承
  • “队员”(斜体字)是个抽象类,不提供实例对象。

注意:在UML中子类只需要些那些自己特有的属性和方法,因为继承就表明拥有父类的属性,同时父类的(公有、保护)方法会被子类继承并应用。


依赖

当在一个类中使用了另一个类时,我们称之为依赖。依赖用虚线连接,用尖箭头指向依赖的目标。比如,一个“系统(System)”的“显示表单(DisplayForm)”功能依赖于“表单类(Form)”:

依赖示例图


聚合

一个类有时是由几个部分类组成的,这种关系是一种“部分-整体”的关联,我们称之为“聚合”。聚合与“组成”有些类似,区别主要是聚合并不限定“部分类”只能归属于自己,说白了“聚合”是没有占有欲的,它仅仅表达它组成了我,但没有要求它只属于我。而“组成”要求“部分类”只能属于自己:

聚合示例图

  • 整体和部分之间用实线连接,且用空心菱形箭头指向整体。

聚集跟关联一样,也能表达“Or”的约束,表达方式一样,“在两个部分的连线中间连接一条虚线,并写上{or}”,其表示整体包含两者间的其中一个。


组成

组成时强类型的聚合,组成有极强占有欲,要求部分必须只能属于自己,即只能属于一个整体。组成是表达类内部结构的一种方式,用于“组成结构图”(UML1.x也称为语境图)中。其UML用实线连接部分和整体,并用实心菱形箭头指向整体:

组成示例图


实现

类由属性和方法(接口)组成,实现表达的就是类与接口间的关系。UML用虚线连接类和接口,并用空心箭头指向接口,比如,“洗衣机(WashineMachine)”实现了“控制旋钮(ControlKnob)”:

实现示例图

  • 实现的表达与继承类似,只是实现用的是虚线。

还有一种表示法(省略表示法),将接口表示为小圆圈,又称为棒糖图(lollipop diagram),这也是我比较喜欢的一种表达方式:

棒糖图示例图

那么接口的出现必然要被使用,比如一个“人(Person)”使用“控制旋钮”,用UML表达如下:

使用接口示例图

  • 可以发现使用接口的表达方式与依赖一样,可以理解为:“人”需要通过“控制旋钮”才能使用“洗衣机”,因此“人”依赖于“控制旋钮”。

还有一种跟“棒糖图”结合的表达使用接口的方式,这也是我最喜欢的方式:

棒糖图的使用示例图


结语

学习UML建模对于程序员来说有莫大帮助,可以帮助自己梳理程序,将思绪可视化表达出来,有助于其开发复杂的大型程序。

同时学习UML建模也有助于技术经理、架构师、研发工程师等技术相关人员间的沟通,降低“知识落差”带来的沟通困难,能有效提高开发出一个符合大家预期的系统的概率。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年5月23日2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 关联
    • 约束
      • 关联类
          • 多重性
            • 限定关联
              • 自身关联
              • 继承和泛化
              • 依赖
              • 聚合
              • 组成
              • 实现
              • 结语
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档