极客时间已完结课程限时免费阅读

09丨软件设计实践:如何使用UML完成一个设计文档?

09丨软件设计实践:如何使用UML完成一个设计文档?-极客时间

09丨软件设计实践:如何使用UML完成一个设计文档?

讲述:李智慧

时长10:58大小10.04M

在上一篇文章中,我们讨论了为什么要建模,以及建模的 4+1 视图模型,4+1 视图模型很好地向我们展示了如何对一个软件的不同方面用不同的模型图进行建模与设计,以完整描述一个软件的业务场景与技术实现。但是软件开发是有阶段性的,在不同的开发阶段用不同的模型图描述业务场景与设计思路,在不同阶段输出不同的设计文档,对于现实的开发更有实践意义。
软件建模与设计过程可以拆分成需求分析、概要设计和详细设计三个阶段。UML 规范包含了十多种模型图,常用的有 7 种:类图、序列图、组件图、部署图、用例图、状态图和活动图。下面我们讨论如何画这 7 种模型图,以及如何在需求分析、概要设计、详细设计三个阶段使用这 7 种模型输出合适的设计文档。

类图

类图是最常见的 UML 图形,用来描述类的特性和类之间的静态关系。
一个类包含三个部分:类的名字、类的属性列表和类的方法列表。类之间有 6 种静态关系:关联、依赖、组合、聚合、继承、泛化。把相关的一组类及其关系用一张图画出来,就是类图。
类图主要是在详细设计阶段画,如果类图已经设计出来了,那么开发工程师只需要按照类图实现代码就可以了,只要类方法的逻辑不是太复杂,不同的工程师实现出来的代码几乎是一样的,这样可以保证软件的规范、统一。在实践中,我们通常不需要把一个软件所有的类都画出来,把核心的、有代表性的、有一定技术难度的类图画出来,一般就可以了。
除了在详细设计阶段画类图,在需求分析阶段,也可以将关键的领域模型对象用类图画出来,在这个阶段中,我们需要关注的是领域对象的识别及其关系,所以用简化的类图来描述,只画出类的名字及关系就可以了。

序列图

类图之外,另一种常用的图是序列图,类图描述类之间的静态关系,序列图则用来描述参与者之间的动态调用关系。
每个参与者有一条垂直向下的生命线,这条线用虚线表示,而参与者之间的消息也从上到下表示其调用的前后顺序关系,这正是序列图这个词的由来。每个生命线都有一个激活条,只有在参与者活动的时候才是激活的。
序列图通常用于表示对象之间的交互,这个对象可以是类对象,也可以是更大粒度的参与者,比如组件、服务器、子系统等,总之,只要是描述不同参与者之间交互的,都可以使用序列图,也就是说,在软件设计的不同阶段,都可以画序列图。

组件图

组件是比类粒度更大的设计元素,一个组件中通常包含很多个类。组件图有的时候和包图的用途比较接近,组件图通常用来描述物理上的组件,比如一个 JAR,一个 DLL 等等。在实践中,我们进行模块设计的时候更多的是用组件图。
组件图描述组件之间的静态关系,主要是依赖关系,如果想要描述组件之间的动态调用关系,可以使用组件序列图,以组件作为参与者,描述组件之间的消息调用关系。
因为组件的粒度比较粗,通常用以描述和设计软件的模块及其之间的关系,需要在设计早期阶段就画出来,因此组件图一般用在概要设计阶段

部署图

部署图描述软件系统的最终部署情况,比如需要部署多少服务器,关键组件都部署在哪些服务器上。
部署图是软件系统最终物理呈现的蓝图,根据部署图,所有相关者,诸如客户、老板、工程师都能清晰地了解到最终运行的系统在物理上是什么样子,和现有的系统服务器的关系,和第三方服务器的关系。根据部署图,还可以估算服务器和第三方软件的采购成本。
因此部署图是整个软件设计模型中,比较宏观的一种图,是在设计早期就需要画的一种模型图。根据部署图,各方可以讨论对这个方案是否认可。只有对部署图达成共识,才能继续后面的细节设计。部署图主要用在概要设计阶段

用例图

用例图主要用在需求分析阶段,通过反映用户和软件系统的交互,描述系统的功能需求。
图中小人形象的元素,被称为角色,角色可以是人,也可以是其他的系统。系统的功能可能会很复杂,所以一张用例图可能只包含其中一小部分功能,这些功能被一个矩形框框起来,这个矩形框被称为用例的边界。框里的椭圆表示一个一个的功能,功能之间可以调用依赖,也可以进行功能扩展。
因为用例图中功能描述比较简单,通常还需要对用例图配以文字说明,形成需求文档。

状态图

状态图用来展示单个对象生命周期的状态变迁。
业务系统中,很多重要的领域对象都有比较复杂的状态变迁,比如账号,有创建状态、激活状态、冻结状态、欠费状态等等各种状态。此外,用户、订单、商品、红包这些常见的领域模型都有多种状态。
这些状态的变迁描述可以在用例图中用文字描述,随着角色的各种操作而改变,但是用这种方式描述,状态散乱在各处,不要说开发的时候容易搞错,就是产品经理自己在设计的时候,也容易搞错对象的状态变迁。
UML 的状态图可以很好地解决这一问题,一张状态图描述一个对象生命周期的各种状态,及其变迁的关系。如图所示,门的状态有开 opened、关 closed 和锁 locked 三种,状态与变迁关系用一张状态图就可以搞定。
状态图要在需求分析阶段画,描述状态变迁的逻辑关系,在详细设计阶段也要画,这个时候,状态要用枚举值表示,以指导具体的开发。

活动图

活动图主要用来描述过程逻辑和业务流程。UML 中没有流程图,很多时候,人们用活动图代替流程图。
活动图和早期流程图的图形元素也很接近,实心圆代表流程开始,空心圆代表流程结束,圆角矩形表示活动,菱形表示分支判断。
此外,活动图引入了一个重要的概念——泳道。活动图可以根据活动的范围,将活动根据领域、系统和角色等划分到不同的泳道中,使流程边界更加清晰。
活动图也比较有普适性,可以在需求分析阶段描述业务流程,也可以在概要设计阶段描述子系统和组件的交互,还可以在详细设计阶段描述一个类方法内部的计算流程。

使用合适的 UML 模型构建一个设计文档

UML 模型图本身并不复杂,几分钟的时间就可以学习一个模型图的画法。但难的是如何在合适的场合下用正确的 UML 模型表达自己的设计意图,形成一套完整的软件模型,进而组织成一个言之有物,层次分明,既可以指导开发,又可以在团队内外达成共识的设计文档。
下面我们就从软件设计的不同阶段这一维度,重新梳理下如何使用正确的模型进行软件建模。
需求分析阶段,主要是通过用例图来描述系统的功能与使用场景;对于关键的业务流程,可以通过活动图描述;如果在需求阶段就提出要和现有的某些子系统整合,那么可以通过时序图描述新系统和原来的子系统的调用关系;可以通过简化的类图进行领域模型抽象,并描述核心领域对象之间的关系;如果某些对象内部会有复杂的状态变化,比如用户、订单这些,可以用状态图进行描述。
概要设计阶段,通过部署图描述系统最终的物理蓝图;通过组件图以及组件时序图设计软件主要模块及其关系;还可以通过组件活动图描述组件间的流程逻辑。
详细设计阶段,主要输出的就是类图和类的时序图,指导最终的代码开发,如果某个类方法内部有比较复杂的逻辑,那么可以用画方法的活动图进行描述。
下一篇文章我会通过一个示例模板为你展示设计文档的写法和 UML 模型在文档中的应用。

小结

UML 建模可以很复杂,也可以很简单,简单掌握类图、时序图、组件图、部署图、用例图、状态图、活动图这 7 种模型图,根据场景的不同,灵活在需求分析、概要设计和详细设计阶段绘制对应的模型图,可以实实在在地做好软件建模,搞好系统设计,做一个掌控局面、引领技术团队的架构师。
画 UML 的工具,可以是很复杂的,用像 EA 这样的大型软件设计工具,不过是收费的,也可以是 draw.io 这样在线、免费的工具,一般来说,都建议先从简单的用起。

思考题

你现在开发的软件是否会用到 UML 建模呢?如果没有,你觉得应该画哪些 UML 模型?又该如何画呢?
欢迎你在评论区写下你的思考,我会和你一起交流,也欢迎把这篇文章分享给你的朋友或者同事,一起交流进步吧!
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 21

提建议

上一篇
08丨软件设计的方法论:软件为什么要建模?
下一篇
10 | 软件设计的目的:糟糕的程序员比优秀的程序员差在哪里?
unpreview
 写留言

精选留言(26)

  • 台风骆骆
    2019-12-09
    本章学习总结: 1、基本上开发分为需求分析、概要设计、详细设计阶段。 2、常用的UML图有类图、时序图、活动图、用例图、组件图、部署图、状态图七种。 类图是用来描述类之间的关系以及类中包含的属性和方法的,可以在需求分析阶段的领域模型用简化的类图来表示,详细设计阶段详细描述类图。 时序图是用来描述类、组件、模块之间的调用关系的,可以在需求分析、概要设计、详细设计都用得到。 活动图则是表达了过程和业务逻辑的,有点像流程图,在三个阶段都可以应用。 用例图是用来表达用户与软件系统的交互,用来表达这个软件系统的功能需求。一般用于需求分析。 组件图是表达了各个组件之间的关系,一般是依赖关系,是静态的,如果要表达调用关系需要用时序图或活动图,一般用于概要设计阶段。 部署图是用于表达物理上面的软件部署情况,一般用于概要设计阶段。 状态图则是表达某个组件或某个类的状态迁移情况。可以用于详细设计和需求分析阶段。 3、不同阶段需要描述的东西不一样,用的图也不一样相同。
    展开
    15
  • To be is to do
    2019-12-09
    老师,可以推荐一下 mac上做UML,时序图的软件吗?

    作者回复: http://astah.net/ https://www.draw.io/

    共 5 条评论
    15
  • Paul Shan
    2019-12-09
    我现在自己写代码基本不画图,主要因为写的软件不够复杂(Android开发)。 我画类图和时序图主要是用来分析别人写的代码,画得过程中往往能搞清楚代码的意图。
    10
  • golangboy
    2019-12-10
    老师, 1.设计模式的图例只适合画静态类图? 2.详细设计阶段是要确定软件的细节和逻辑的基本框架,用设计模式可以提高程序的扩展性,我这样理解对吗? 3.实际开发中,有很多都是那种需求都不明确,探索性的,随时要变,甚至推倒重来。像这种情况,我也不可能一开始就有全局的视野,有啥好的实践经验或者推荐?
    展开

    作者回复: 1 还可以画时序图 2 是的。不过有的设计模式在概要设计阶段就需要了,像策略模式,可能会影响整个系统的架构 3 越是随时要变的,越是更要有全局视野,不然变来变去迷失了。你可以先设计一个你认为的蓝图规划,然后随着变化调整你的设计。

    共 2 条评论
    6
  • 睡浴缸的人
    2020-01-17
    以前做业务开发的时候被业务逼着走,没有什么意识。后来做独自坐通用模块时,感觉这样不行,看了点软件工程的书,慢慢开始画UML图进行设计,设计完后有时候写代码简直如尿奔~

    作者回复: 😁

    共 2 条评论
    4
  • 卡特
    2020-02-15
    小结一下 uml图主要有7类 我用的mac,工具astash 或者planuml 从需求分析,概要设计,详细设计依次画这些图 1,用例图 体现角色和软件系统的功能 2,活动图 体现核心流程 3, 状态图 体现核心状态变化 4,部署图 软件的物理结构 5,组件图 软件的模块结构 6,时序图 核心和逻辑 7,类图 领域模型和具体功能设计 可以比较好的为软件建模
    展开
    3
  • alex
    2019-12-23
    活动图跟时序图这两个有点分不清,老师能给讲下区分么?
    共 1 条评论
    2
  • Heidi
    2019-12-09
    计算机类专业大一大二内容
    共 2 条评论
    2
  • Peter
    2021-06-19
    一直有个问题没搞清楚,就是关联关系和组合关系之间的关系区别是什么,我怎么觉得都是类A中包含一个成员变量类B

    作者回复: 站在业务视角看: 用户和订单关联,但是不能说用户由订单组成。但是订单可以由订单项组成。

    1
  • 丁丁历险记
    2020-10-18
    太多的细节,没法用这些来描述。往往是客户在反复使用后调整出来的。
    1
  • 杯莫停
    2020-08-18
    设计一个东西,先画出图,按照流程去实现。有些像逻辑判断,结果导向会清晰很多。Bug多都是因为没有一个全局概念,写代码耦合性越来越高。还有就是画图比较有说服力。
    1
  • 杯莫停
    2020-08-18
    我们一般都是架构师一个PPT上面画些流程图,然后粗略讲讲,然后我们开发的时候就靠自己想象力了。
    1
  • Seven.Lin澤耿
    2020-05-12
    我们会画图,但是没按照规范,应该是四不像,但是也能用😂

    作者回复: 👍

    1
  • 芒果少侠
    2020-03-23
    思考题 你现在开发的软件是否会用到 UML 建模呢?如果没有,你觉得应该画哪些 UML 模型?又该如何画呢? ---- 我的回答:目前在工作中基本用不到UML建模。这可能是因为我目前的开发任务比较简单,都是基于现有的大项目框架来进行新增需求或修改需求开发。系统部署的建模也暂时没有涉及到。 但我相信,随着工作的深入,我接触到的工作将会更上层,到时候,面对复杂业务场景,我只有提前做好软件建模设计工作,才能进一步着手的实际开售。
    展开
    1
  • realwuxing
    2020-01-25
    李老师您好,请问架构设计中一般会有的总体设计分层图,技术架构分层图以及逻辑架构图(系统之间的关系) ,这些所起的主要作用?
    1
  • 灰灰
    2019-12-19
    打卡
    1
  • 靠人品去赢
    2019-12-18
    这个我最常用序列图设计功能和UML设计数据库来着。。。。 总算有一份把把UML说的全一点文章了,最开始不怎么画图,但是设计到一个稍微复杂点的和别的系统有交互的功能从0到1,画一下序列图什么确实有帮助。把这个过程能梳理清楚一些,比直接写代码要头脑更清楚。
    1
  • 秦凯
    2019-12-09
    接触到的项目基本都没有这样全面可以窥探系统全貌的架构设计文档。而且实际工作中,项目组小伙伴们接到各自的需求都是在各自的点上做开发,很少从面或体上面去考虑需求、设计和实现,这样就导致判断分支、冗余代码、不必要的复杂逻辑越来越多。大家有没有好的办法走出这种困境?
    共 2 条评论
    1
  • 老实人Honey
    2023-02-25 来自广东
    业务架构图,时序图,泳道图
  • 布拉姆
    2021-03-17
    组件是系统中遵循一组接口且提供实现的一个物理部件,通常指开发和运行时类的物理实现。表示实际存在的、物理的物件,可以是:源代码、子系统、动态链接库等,组件一般都包含很多类并实现很多接口。 子系统是组件,通常包括许多更小的组件,是一个大的组件。 包多用于将类分组。类似于命名空间,在同一包中名字唯一。
    展开