参考资料:
https://zhuanlan.zhihu.com/p/669466741
UMLChina《软件方法》
https://www.processon.com/knowledge/classdiagram
目录
[泛化(is-a)- 空心三角箭头](#泛化(is-a)- 空心三角箭头)
继承(Generalization/Inheritance)-实线+空心三角箭头
类关系举例图(https://cloud.tencent.com/developer/article/2105150)
类关系总结图(https://www.processon.com/knowledge/classdiagram)
[同步消息(Synchronous Message)](#同步消息(Synchronous Message))
[异步消息(Asynchronous Message)](#异步消息(Asynchronous Message))
[返回消息(Return Message)](#返回消息(Return Message))
5.C-分析
--软件设计的两种复用形式
核心域的复用
真正涉及到业务的核心域知识,是复用的最重要领域。
但大部分软件研发人员,这一步往往都没有做好。
非核心域的复用
目前大多数软件组织的复用仅停留在基础设施领域的复用,即使有自己的"内部开发平台",也仅是根据自己所开发系统的需要对基础设施作进一步封装。
这种非核心域的复用,各个公司组织都大同小异,没有长久的竞争优势。
画分析类图的时候要拆分核心域与非核心域,避免过于复杂,互相干扰。
这里的类,可以理解为需求中涉及或接触到的系统对象。
--分析类
三种构造型

- 边界类:输入、输出,及简单的过滤;
- 控制类:控制用例流,为实体分配责任;
- 实体类:系统的核心,封装领域逻辑和数据。
一次交互回合
- 执行者先把消息发给边界类对象,边界类对象能履行的就履行,无法履行的责任,再发给控制类对象。
- 控制类对象就像总裁办,不做具体工作,只是将责任分解后分配给实体类对象。
- 实体类按照它们之间的耦合程度聚集成若干聚合(也有可能一个类单独形成聚合)。
- 控制类对象发送消息时,先发给聚合的整体对象(也称聚合根),再由聚合根分配给聚合内的其他对象。
- 最后,由边界类对象反馈信息,完成一个交互回合。
分析建议
对于类的分析,和关系型数据库的表结构分析是类似的,得到的类和表也基本是一一对应的。
这里,建议按照领域模型来区分类,这样得到的类,是最符合领域的特性的,也一定是最契合业务发展的(业务本身就是在其领域的基础上做流程变化)。
--"彩色建模"思想的四种类
事物
其状态值得关注,在其身上发生领域事件。
描述
对象较少,封装某方面的规则,状态变化不值得关注。
时段时刻
对象多,属性不应修改。
角色
解耦事物与时段时刻。
这种建模的套路是:从"时段时刻"开始,找出后面的"角色"和"事物";
在"描述"的关系上找到"事物"。
--类图
类不能像一个过程,而应该是一个对象。(设计源于需求,高于需求)


类名
抽取用例规约中的名词和事件,使用名词短语为类命名。例如,"Customer"、"Order"等。注意:

- 命名以专业术语为准。
- 确保名称简洁,不要带冗余信息(不要加类、C、表、库、信息等词)。
- 类名应该准确清晰的反映出问题域中的概念。
- 名称中的每个词的首字母应大写。
- 使用正体名称来表示可实例化的类。
- 使用斜体名称表示抽象的类。
- 英文命名则用单数。
- 多处重复的同一概念,命名要一致(如顾客与客户)。
属性
列出类的关键特征或数据成员,包括数据类型。
属性通常放在类名的下方,属性名前不要加类名(冗余),格式为"属性名: 数据类型",例如,"name: String"。
语法
可见性\] 属性名称 \[:数据类型\] \[=初始值\] \[{属性字符串}
(1)可见性
可见性用于控制该属性被类的外部成员的可访问性。主要有以下四种情况:
- +:公有属性,其它类可以访问该属性;
- -:私有属性,不能被其它类访问(默认为私有);
- #:保护属性,只能被本类及其派生类访问;
- ~:包内可见,可以被本包中的其它类访问;
(2)属性名称
能够准确描述类特征的一个标识符,属性名通常是一个名词或名词短语。
一般单字属性使用小写字母,多字属性从第2个单词开始,每个单词的第一个字符要大写。
(3)数据类型
属性所属的数据类型,如布尔类型、整型、浮点型,也可以是用户自定义的类型。
(4)初始值
属性的默认值,在类的实例没有赋其它值时,将采用该值作为该属性的值。
(5)属性字符串
用来指定该属性的其它信息。任何希望进一步描述该属性又没有合适的地方时都可以放在此处。
以上关于属性的描述内容虽然很多,但一般属性的可见性和属性名称是必需的部分。
属性是否直接描述类的特征

是否有复杂结构或1对多的属性

如果属性再分解就得到其他领域的概念(如人的姓名,姓名再分解就是 string 类型,属于其他领域知识),那么这个属性可以留在类中。
如果可以继续分解成本领域的概念(比如人的组织,组织可继续分解),可以考虑把这个属性独立出去变成另一个类。
多重性大于一的属性,可以再分解出其他类,比如人可以有多个电话,那么电话可以是另一个类(联系方式)。
属性是否对类的所有对象都有意义

分析类属性时,不能完全照搬某张文件表单里的字段,他们不一定是一个领域的。
透过现象(非核心域的实现手段)看本质(核心域的机制、专业术语)。
属性要能直接用于描述类,在划分属性从属于哪个类时,试试"[类]的[属性]"能否说通。
操作(或方法)
列出类可执行的操作或函数,包括返回类型和参数列表。
方法一般位于属性的下方,格式为"方法名(参数): 返回类型"。
例如,"placeOrder(productID, quantity): Boolean"。
语法
可见性\] 操作名称 \[(参数表)\]\[:返回类型\]\[{属性字符串}
( 1 )可见性
与属性相同,规定该操作的可访问范围。
操作的可见性也是有+(公有)、-(私有),#(保护)和~(包内可见)四种。

( 2 )操作名称
用来描述所属类的行为的动词或动词短语。
在UML中,和属性名的表示类似,单字的操作名小写;
多字的操作名,除第一个单词外,其余单词的开头字母要大写。

( 3 )参数表
- 参数表是一些按顺序排列的属性定义了操作的输入;
- 参数表是可选的;
- 参数的定义使用"名称:类型"的定义方式;
- 如果存在多个参数,则将各个参数用逗号隔开;
- 参数可以具有默认值,适用调用时没有提供参数值的情况。
如下面的time,其类型为Date,默认值为currentdate(即当前时间):

( 4 )返回类型
此项为可选项目,即操作不一定必须有返回类型。
但在具体编程语言中使用void关键字来代表这种无返回值的情况。

( 5 )属性字符串
任何在其它地方没有描述清楚的内容都可以在这里进行描述。
使用符号总结:
- --: private
- +: public
- ~: default
- #: protected
- 下划线: static
- 斜体: 抽象 (注意也可以用两个尖括号包裹来表示抽象,比如 ------ <<我是抽象类or接口>>)
- 冒号前是方法名/变量名(根据有无括号区分),冒号后是返回参数/变量类型(根据有无括号区分),如果没有冒号的话表示方法返回空(也有人通过:void表示返空)
其他构成元素
在UML中,一个类通常由名称(Name)、属性(Attribute)和操作(Operation)构成。
除此之外,
类的构成还包含类的职责(Responsibility)、约束(Constraint)和注释(Note)等信息。
类的职责
在UML中,可以在操作部分的下面再添加一个区域,用来说明类的职责,即说明类或其它元素的契约或义务。
创建一个类时,同时声明这个类的所有对象具有相同种类的状态和相同种类的行为,在较高层次上,这些相应的属性和操作正是要完成类的职责和特性。职责可以使用一个短语、一个句子或一段短文的形式来描述。

类的约束
类的约束指定了该类所要满足的一个或多个规则,在UML中,约束使用一个大括号括起来的文本信息:

--接口

- 接口是在没有给出对象的实现和状态的情况下对对象行为的描述;
- 接口包含操作但不包含属性,且它没有对外界可见的关联;
- 一个类可以实现一个或多个接口,从而支持接口所指定的操作;
接口可以使用下面两种形式来表示:

e.g IUser是一个接口,VipUser是一个类,VipUser类要实现接口IUser

--类间的关系
尽量基于静态关系来建立动态关系

泛化(is-a)- 空心三角箭头
泛化类似面向对象中的继承,子类通过继承超类而拥有超类的特征,是一种集合关系,比如,人与男人、女人。

注意警惕拼凑泛化。
识别泛化关系的方法
- 对类与类之间,思考 A 是否是 B 的一种,而 B 是否是 A 的一种。
- 对多个已有的类,抽象出公共部分,形成超类。
- 从一般的类,细化出特殊的子类。
- 尽量不要跨领域形成泛化关系。
继承(Generalization/Inheritance)-实线+空心三角箭头
从子类指向父类即表示一个继承。

从特殊到一般

从一般到特殊

实现(Realization)-虚线+空心三角箭头
从实例指向接口表示一个实现,从实例指向抽象类也表示一个实现。

关联(has-a)-实线箭头
对象通过组装其他对象而拥有其他对象的特征,是个体类间的关系,如人与手、脚。
只有系统负责维护的关系,才构成关联。
泛化和关联,可以视分析场景进行转变,可用于简化模型。

关联关系又可以分为单向关联、双向关联、自关联、聚合关联和组合关联5种情形。
关联的多重性:

多重性是UML中使用最广泛的约束,主要有以下几种形式:
|----------|--------|--------|-----------|
| 形式 | 含义 | 形式 | 含义 |
| 0 | 恰为0 | 0..n | 0到多个 |
| 1 | 恰为1 | 1..n | 1到多个 |
| 0..1 | 0或1 | 3..n | 3到多个,至少3个 |
| n | 0或多个 | 3,5,7 | 3个或5个或7个 |
单向关联(Association)-实线箭头

使用实线箭头表示,可以是单向或双向的。
双向关联(Association)-实线
双向关联关系不再绘制箭头,使用直线直接连接两个类即可,如下面两个类之间的关系即是双向关联关系:

自关联(Association)-实线箭头
自关联关系即一个类与自己进行关联。下面类关系的意思是employee类中有一个为employee类型的leader成员,表示员工的领导:

聚合关联(Aggregation)-实线箭头+空心菱形箭头

从整体指向局部即表示一个聚合。
多个对象和某个对象的关联紧密,视为受其影响的分区(如公司与各个部门)。
但他们的关联是相对较弱的,局部对象是可以脱离整体对象而单独存在的。
组合关联(Composition)-实线箭头+实心菱形箭头

从整体指向局部即表示一个组合,组合又叫合成。
比聚合更严格,"部分"对象跟随"整体"对象销毁而销毁;
"部分"对象只属于一个"整体"对象;
"整体"对象负责"部分"对象的创建与销毁。
依赖-(use-a)-虚线箭头(Dependency)

其他不能视为泛化或关联的类间关系。
从使用者指向被使用者,即一个物体需要通过另一个物体来完成工作,但他们之间没有包含的关系。
类关系举例图(https://cloud.tencent.com/developer/article/2105150)

类关系总结图(https://www.processon.com/knowledge/classdiagram)

--绘制分析类图的步骤

1,研究分析问题领域,确定系统的需求;
2,发现对象与对象类,明确他们的含义和责任,确定属性和操作。
3,发现类之间的静态联系;
4,设计类与联系;
5,绘制类图并编制相应的说明。
--分析序列图

与业务序列图的对比

序列图元素
- 消息传入:类的操作--责任
- 消息传出:类完成操作所需合作--协作
- 位置:每个用例下面,对应用例的路径
- 基本路径:一张图
- 简单的扩展点:可以合并到基本路径图
- 复杂扩展点:单独一张图,和基本路径图间链接
- 控制类只分配责任


责任分配的交互原则
专家原则--资源决定消息内容
独立完成
分解大责任
委托给其他领域
老板原则--由老板发送消息给我
向聚合/组合结构所发的消息,先通过整体对象处理和中转
减少耦合,减少修改引起的波动
判定聚合/组合要谨慎!
可视原则--只发消息给朋友
--分析状态图
帮助定义恰当责任
不同视角对类的描述

状态图元素

与活动图的对比

状态
表现相同行为的属性值和链接的组合
历史状态
历史:记住最近一次离开时最后所处的子状态
浅历史:仅记住同层
深历史:记住最精确子状态
并发状态
从不同维度分割属性值组合,不同分区的状态并存(AND)
入口动作和出口动作

迁移
结构

执行顺序

哪些类值得画状态图
全方位考虑建模的可能性和必要性
核心类
状态多事物(彩色建模)≈实体≈责任起点≈聚合的根
边界类
有时代表的是整个系统的状态,有时不是
质量要求很高的系统→每个类
画图要点
- 从类名思考修饰词(形容词)
- 从行为思考状态变化
- 从状态属性思考状态名称
- 优先使用原生形容词,防止换汤不换药
序列图的组成部分
角色(Actor)
通常指外部与系统交互的实体,可以是人或其他系统。
对象(Object)
系统内部的实体,通常是指类的实例。在序列图中,对象通过一个矩形框表示,对象的命名方式有三种:
对象名和类名,例如:dispatcherServlet:DispatcherServlet
只显示类名,即表示它是一个匿名对象,例如::DispatcherServlet
只显示对象名不显示类名,例如:dispatcherServlet
生命线(LifeLine)
从对象框向下延伸的虚线,表示对象在时间线上的存在。生命线上的不同点表示不同的时间点。
激活(Activation)

通常在生命线上显示为一个较窄的矩形。它表示对象在一段时间内是活跃的,即正在响应或执行某个操作。
消息(Message)

对象之间交互的基本单位,表示为带箭头的线。消息可以是同步,异步,或返回消息。
同步消息(Synchronous Message)
发送者在发送消息后,必须等待接收者完成相应的操作后才能继续。
异步消息(Asynchronous Message)
发送者发送消息后,可以继续执行后续的操作,不需等待接收者。
返回消息(Return Message)
接收者完成操作后,将结果返回给发送者。
交互框
UML在2.0时在时序图中加入了交互框。
交互框用来解决交互执行的条件和方式,它允许在序列图中直接表示逻辑组件,用于通过指定条件或子进程的应用区域,为任何生命线的任何部分定义特殊条件和子进程。
组合片段共有13种,名称及含义如下:
|--------------|--------|-------------------------------------------------------------------------------------------------------------------------------------|
| 片段类型 | 名称 | 说明 |
| Opt | 选项 | 包含一个可能发生或可能不发生的序列。可以在临界中指定序列发生的条件。 |
| Alt | 抉择 | 包含一个片段列表,这些片段包含备选消息序列。在任何场合下只发生一个序列。可以在每个片段中设置一个临界来指示该片段可以运行的条件。else 的临界指示其他任何临界都不为 True 时应运行的片段。如果所有临界都为 False 并且没有 else,则不执行任何片段。 |
| Loop | 循环 | 片段重复一定次数。可以在临界中指示片段重复的条件。Loop 组合片段具有"Min"和"Max"属性,它们指示片段可以重复的最小和最大次数。默认值是无限制。 |
| Break | 中断 | 如果执行此片段,则放弃序列的其余部分。可以使用临界来指示发生中断的条件。 |
| Par | 并行处理 | 片段中的事件可以交错。 |
| Critical | 关键 | 用在 Par 或 Seq 片段中。指示此片段中的消息不得与其他消息交错。 |
| Seq | 弱顺序 | 有两个或更多操作数片段。涉及同一生命线的消息必须以片段的顺序发生。如果消息涉及的生命线不同,来自不同片段的消息可能会并行交错。 |
| Strict | 强顺序 | 有两个或更多操作数片段。这些片段必须按给定顺序发生。 |
| Consider | 考虑 | 指定此片段描述的消息列表。其他消息可发生在运行的系统中,但对此描述来说意义不大。在"Messages"属性中键入该列表。 |
| Ignore | 忽略 | 此片段未描述的消息列表。这些消息可发生在运行的系统中,但对此描述来说意义不大。在"Messages"属性中键入该列表。 |
| Assert | 断言 | 操作数片段指定唯一有效的序列。通常用在 Consider 或 Ignore 片段中。 |
| Neg | 否定 | 此片段中显示的序列不得发生。通常用在 Consider 或 Ignore 片段中。 |
序列图的作用
确认和丰富逻辑表达
用于确认和丰富一个使用语境的逻辑表达,如用例的一部分或控制流。
细化用例表达
将用例表达的需求转化为更正式层次的精细表达。
描述类职责分配
根据对象之间的交互关系来定义类的职责,构成特定的用例。
绘制序列图的步骤
- 划清边界,识别交互语境:确定绘制时序图的范围和背景。
- 梳理角色和对象:确定时序图中的角色和对象。
- 确定对象间的交互消息:明确对象之间的交互消息。
