ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

UML设计文档实战:类图、时序图与状态图避坑指南

UML设计文档实战:类图、时序图与状态图避坑指南 简介这是一份UML面向对象分析与设计课程的大作业资料围绕“简易教学管理系统”开展完整建模面向计算机、软件工程等专业学生适合用于课程设计或期末项目参考。文档从需求陈述入手覆盖选课管理和成绩管理两大业务细化课程表录入、学生选课注册、课程与师生信息查询、成绩录入统计与报表生成等场景并逐步绘制顶层用例图、选课管理用例图、成绩管理用例图、顺序图、课程管理对象类图、人事信息对象类图、学生选课登记状态图、活动图、组件图和部署图同时介绍Rational Rose建模工具的使用与正向工程思路。资源包为单个docx文件压缩后约3.44MB包含建模步骤、任务分解和模型图例便于修改复用。目前已有185人学习下载是UML实践与课程设计的实用参考。通过仿照其中的模型读者可以理解UML主要图型的应用场景掌握用Rational Rose完成需求建模、架构建模及设计文档撰写的方法。1. 为什么说UML文档不是画图而是让设计矛盾提前暴露项目评审会上最常见的翻车现场不是你代码写得不行而是你拿着用例图和类图讲设计开发问了一句「这个虚线箭头到底是不是 new 了一个对象」你答不上来。更常见的情况是图很好看评审也过了代码写了一个月后发现两个模块的依赖关系完全不是当初画的那样返工成本直接翻倍。UML面向对象分析与设计这份文档解决的就是这个问题在动手写代码之前把类之间的关系、对象之间的协作、状态之间的迁移用标准化的图形语言固定下来让设计矛盾在评审阶段就暴露而不是等代码跑起来才爆雷。这份文档适合三类人一类是被要求补交设计文档、之前靠脑子硬记代码结构的开发者一类是准备软考中级、需要系统掌握UML建模规则的考生还有一类是需要在项目中做设计评审、却总被无休止的讨论拖垮的架构师。核心不是学会画几种图而是搞清楚每种图回答什么问题、画到什么粒度、什么时候不值得画。2. UML静态结构建模类图、包图与对象图的高频用法和判读标准2.1 类图箭头含义先把六种关系一次性分清类图是UML里出镜率最高、评审时被追问最多的一种图。很多项目文档里画了一堆类图但箭头全是乱的实线虚线混用菱形箭头乱飞。类图的关系有六种每种对应明确的代码语义搞混了评审必被怼。关系图形代码体现判定标准继承实线空心三角箭头箭头指向父类extends「是一个」关系子类可替换父类实现虚线空心三角箭头箭头指向接口implements类承诺遵守接口契约依赖虚线普通箭头箭头指向被依赖方方法参数、局部变量、静态调用瞬时关系不持有对方引用关联实线普通箭头箭头指向被关联方类持有对方成员引用长期关系作为字段存在聚合实线空心菱形菱形端指向整体ListMember整体创建但可脱离弱拥有部分可独立存在组合实线实心菱形菱形端指向整体Order持有OrderItem同生共死强拥有部分不可独立存在判读关系最简单的办法不是看图形而是问两个问题。第一个问题如果A类删掉了B类还能不能用能是依赖或聚合不能是组合。第二个问题这个关系是临时的还是长期的方法参数里用了一下是依赖作为类的字段持有是关联。这两个问题答完画出来的类图基本不会犯大错。实际项目里最常见的错误是把依赖画成关联。比如一个OrderService调用了EmailSender的静态方法只是发送一封邮件这明显是依赖关系虚线箭头就够了。但很多人习惯性地画成实线关联导致评审时被问「OrderService 为什么要持有 EmailSender 这个字段」——它根本不持有只是临时调用。2.2 包图模块边界画清楚依赖方向才可控类图画到几十个的时候评审已经没法看了。这时候需要用包图把类的归属和依赖方向理清楚。包图本质上是类图的高层聚合视图但不是把类图缩小而是用包作为组织单元表达包与包之间的依赖关系。画包图有一个硬性要求不允许循环依赖。A包依赖B包B包依赖C包C包又依赖A包这样的模块结构在代码评审时一定会被挑战。我一般画包图之前先列一张依赖方向表把「谁依赖谁」写成文字确认没有环再落图。画包图时还要注意一个粒度问题包下面要不要继续展示类展示到什么深度常见做法是包内部只显示核心类也就是被外部引用的那些类实现细节类不画出来。比如用户模块的包图只画UserService、UserRepository这个层次的对外接口类UserValidator这种内部工具类不要出现在包图里否则图面信息过载失去抽象的意义。2.3 对象图什么时候值得画什么时候是浪费时间对象图是类图的实例快照展示某一时刻各个对象的具体状态和关系。它在文档里的地位有点尴尬——画了显得专业但实际价值有限。对象图真正有价值的使用场景只有两个一个是描述复杂数据结构在运行时的形态比如订单系统里订单、订单项、商品三者关联关系的瞬间快照另一个是配合时序图说明某个关键场景下的对象协作关系。其他情况下画对象图基本是在凑篇幅。评审专家看对象图时关注的是「这个快照和类图的定义是否一致」如果类图里定义的是聚合关系对象图里画成了独立的两个对象而且没有归属连线那就是自相矛盾。所以在交付文档里对象图应该出现在类图之后作为类图关系的实例验证而不是单独成章。画对象图时注意对象名要带下划线格式是对象名:类名类名可以省略但连线上要标注具体的属性值这样才能表达「快照」语义。3. UML动态行为建模用例图、时序图与状态图怎么选怎么画3.1 用例图不是流程图边界和参与者才是核心用例图是动态行为建模的入口但它也最容易被画错。很多人把用例图画成了流程图把「用户点击登录按钮→系统校验密码→跳转主页」这种操作步骤画进去这是概念性错误。用例图回答的问题是「谁可以用系统做什么」不是「系统内部怎么做」。画用例图的第一步是圈系统边界。一个方框代表系统方框外是参与者Actor方框内是用例椭圆。这一步看起来简单但边界画在哪里直接决定用例粒度。比如一个电商后台参与者和用例的关系是顾客使用下订单、支付、查询订单运营人员使用商品上架、订单审核、数据导出。如果把「支付」拆成「发起支付」「支付回调」「支付结果查询」三个用例粒度就太细了评审时会被告知这是功能点列表不是用例图。判断用例粒度是否合适的标准一个用例能否给参与者带来可观测的、完整的业务价值。不能带来完整价值的不要画成用例。用例图里还包括include和extend两种关系include表示一个用例一定会包含另一个用例比如「下订单」一定会包含「校验库存」extend表示条件触发的扩展比如「下订单」在库存不足时扩展出「触发缺货登记」。这两种关系实际画的时候要克制能用文字说明的不要强行用箭头表达。3.2 UML中的动态结构图有哪些时序图、通信图、状态图、活动图热搜词「uml中的动态结构图包括」对应的答案在UML规范里是指交互图和行为图这个大分支。具体拆开动态结构图包括时序图顺序图、通信图协作图、状态图、活动图这四种图分别回答不同的问题。时序图强调消息的时间顺序通信图强调对象间的连接关系状态图强调单个对象的状态迁移活动图强调业务流程的流转。实际项目文档里时序图的使用频率远高于其他三种。原因很简单评审时讨论「先做什么后做什么」「谁调用谁」最直观的表达方式就是时序图。活动图在业务流程需要跨角色、带分支判断时才有价值比如审批流、异常处理流。通信图由于时序图已经覆盖了大部分场景现在项目文档里很少单独出现如果要用也是在时序图之外需要强调对象间的静态连接关系时。状态图是最容易被忽视但最能救命的一种图。它适用于单个对象状态较多的场景最典型的是订单状态机待支付、已支付、已发货、已完成、已取消、退款中、已退款。这种图不画代码里就是一堆散落的状态判断评审时没人能看出状态迁移是否完整。而活动图我一般只在用例的流程分支复杂时附带补充交互流程简单时直接用文字描述就够了。3.3 时序图画到什么粒度消息是协作的对象间传递不是函数调用清单时序图画错最多的地方是把时序图画成了接口调用顺序表。一个箭头一个接口方法每个方法回调都画出来结果一张A4纸挤了几十个箭头评审时没人看得下去。正确的画法是消息代表对象之间的协作行为不是函数签名。同一模块内部的私有方法调用、字段赋值这类细节不该出现在时序图上。画时序图我习惯遵循三个原则。第一个原则只画跨越对象边界、有业务含义的消息。比如OrderService调用InventoryClient的checkStock这是跨对象协作值得画但OrderService内部先调this.validate()再调this.calculatePrice()这是内部逻辑不值得画。第二个原则激活条要画对。每个对象接收消息后处理期间画一条竖线的激活条消息箭头必须指向激活条的顶端返回消息用虚线箭头可省略返回值但调用关系必须清晰。第三个原则能用片段alt、opt、loop表达的不要拆成多条分支。比如登录成功和失败两种返回用alt片段框起来比画两条完整路径清晰得多。时序图里还有一个常被忽略的细节生命线的命名。生命线框里的格式是「对象名:类名」对象名可以省略但类名不能错。评审时被指出「这个生命线叫userService但类名写成了UserService的大小写不一致」虽然是小问题但暴露了文档不严谨。3.4 状态图的边界状态多才需要画别给简单对象设计状态机判断要不要画状态图我有个简单的量化标准一个对象在业务生命周期内是否有超过五个不同的状态且状态之间存在依赖顺序。订单、支付单、审批单这种对象必须画而一个User对象只有「正常」和「停用」两个状态画状态图纯属浪费。画状态图要注意三个点。第一初始状态用一个实心圆表示终止状态用实心圆外加一个圆环这两个标记不能漏。第二迁移弧线上标注「事件[守卫条件]/动作」比如「支付成功[金额已校验]/更新订单状态」这是状态图的规范写法。第三状态图要能回答「状态是否会出现死循环」「是否存在不可达状态」这两个问题评审时这两个问题几乎必问。4. 把设计落成代码从图到代码骨架的映射路径与文档组织4.1 用PlantUML快速生成可评审的类图和时序图实际项目中画UML图我不建议用Visio或 ProcessOn 一笔一笔画。效率太低而且改版时维护成本高。我更推荐用PlantUML这种文本化建模工具图是代码生成的改代码就改图特别适合评审前快速迭代。一份可运行的PlantUML类图代码如下所示startuml 定义类的属性与方法 class Order { - orderNo : String - totalAmount : BigDecimal - status : OrderStatus createOrder(items : ListOrderItem) : Order cancel() : boolean } class OrderItem { - skuId : String - quantity : int - price : BigDecimal } class User { - userId : String - name : String } 组合关系Order 销毁时 OrderItem 一并销毁 Order *-- OrderItem 关联关系Order 持有 User 引用User 可独立存在 Order -- User 依赖关系Order 在方法中使用 OrderStatus Order .. OrderStatus enduml这段代码里*--表示组合关系--表示关联关系..表示依赖关系。-开头的是私有属性开头的是公有方法。运行 PlantUML 生成PNG或SVG的命令很简单plantuml -tsvg order_class.puml -output ../docs/生成后的SVG文件缩放不失真可以直接放进Word文档。PlantUML的图形语法和UML规范并不是完全一一对应使用前最好确认一下你用的符号生成出来的图形是否正确特别是箭头类型。这条命令会输出一个order_class.svg到docs目录时间约12秒。改类名、加属性、换关系类型改完重新执行一次即可这是文本化建模最大的节省。4.2 从类图到Java代码骨架的三个映射规则类图评审通过后下一步是把它变成代码骨架。这个过程有三个映射规则。第一个规则类图中的属性和方法一对一映射为Java的字段和方法签名关系映射到成员引用或方法参数。第二个规则组合关系*--在代码里体现为直接new字段并在构造函数里初始化容器销毁时内容对象没有外部引用来维持生命周期。第三个规则依赖关系不落字段只出现在方法参数、局部变量或静态调用里。以Order和OrderItem为例映射后的Java骨架代码是public class Order { private String orderNo; private BigDecimal totalAmount; private OrderStatus status; // 组合关系Order 创建 OrderItem同生命周期 private ListOrderItem items new ArrayList(); public void addOrderItem(OrderItem item) { this.items.add(item); } } public class OrderItem { private String skuId; private int quantity; private BigDecimal price; }这里Order直接持有ListOrderItem并在自身初始化体现组合关系。如果改成聚合关系OrderItem应该由外部创建后通过构造函数传入而不是在Order内部new。这个区别在代码审查时一眼就能看出来。评审阶段如果发现代码和类图不一致通常不是代码写错而是当初类图的箭头画错了。所以拿到代码后反向核对类图也是验证设计质量的一种手段。4.3 文档怎么组织docx里每个图都要配设计说明而不是光堆图一份合格的UML设计文档不是图集。每张图都必须在图前有一段文字说明这张图解决什么问题、核心设计决策是什么、有哪些备选方案为什么没选。图后要附一段说明解释图里容易误解的地方。比如类图画了组合关系就要说明「为什么OrderItem不能独立存在如果将来要支持单独管理赠品这个组合关系是否要改成聚合关系」。这种设计说明比图本身更有评审价值。我一般组织一份UML设计文档的结构如下表章节内容注意点1. 设计概述系统范围、核心业务场景、技术约束不写背景废话直接说边界2. 用例模型用例图 用例描述表每个用例配套基本流和备选流3. 静态结构包图 类图 对象图类图按模块拆不铺成大图4. 动态行为时序图 状态图活动图按需时序图按业务场景选不按接口选5. 设计约束依赖方向、事务边界、并发策略明确什么不能做这个结构里最关键的是第五部分。很多文档把约束藏在代码里但评审专家明确要求把约束写出来。比如「订单模块不得直接访问用户模块的数据库表」「消息发送必须走MQ不允许同步调用」这类约束写在文档里代码评审时才有依据。5. UML建模常踩的6个坑图是对的评审照样翻车5.1 用例图画成了业务流程被质疑「这不是用例」现象用例图里画了一个大椭圆里面写了一串操作步骤「用户输入账号密码→系统校验→系统返回结果」评审专家直接说这不是用例图这是流程图。原因把用例当成了功能步骤忘了用例是参与者与系统交互的一个完整目标。「登录」才是用例「输入账号密码」是登录的基本流不是用例本身。解决用例图只画椭圆和参与者连线操作步骤写进用例描述表的「基本流」里。如果一个用例的基本流超过四步考虑拆分子用例或用活动图表达流程。5.2 类图箭头全是关联依赖和关联傻傻分不清现象整个类图二十几个类所有关系都是实线箭头评审时被问「A和B之间到底是长期持有还是临时使用」答不上来。原因画图时图省事统一用实线箭头没有区分瞬时依赖和长期关联。这种图在代码落地的指导价值很低因为依赖关系映射为方法参数关联关系映射为字段两者生成的代码完全不同。解决画完类图后做一次自检逐个关系回答「这个类是对方的字段还是只在方法里用了对方」这个判断。答案不明确的关系说明类的职责边界还不清晰先改设计再改图。5.3 时序图画成方法调用清单一张图全是激活条现象时序图里几十条消息每个setter方法都画一个箭头整个人物生命线上密密麻麻全是激活条评审时超时也没讲完。原因没有取舍消息的粒度把代码实现细节当成了对象协作消息。评审专家关心的不是方法名而是业务步骤和对象职责边界。解决删除所有内部方法调用消息。输出评审版时序图时用alt、loop片段压缩分支和循环。如果删完后一张图能控制在十二三条消息以内说明粒度合适超过就再拆一张。5.4 状态图状态太多每个状态都是「已XX」没有迁移条件现象订单状态图里画了十来个状态但每条迁移弧线上只有事件名没有守卫条件和动作。原因把数据库里的状态字段直接搬到了图上没有做抽象。实际代码里的状态迁移往往依赖前置条件比如「已发货」能不能迁到「已完成」要满足「买家已确认收货」这个条件。解决每种状态迁移至少标注「事件 守卫条件 动作」三元组。如果守卫条件过于复杂考虑把条件提取成业务规则对象避免状态图变成代码逻辑的复读机。5.5 文档只有图没有字评审全靠作者现场讲现象交付的docx文档里全是图每张图下面没有文字说明其他成员离线评审时根本看不懂只能拉着作者讲。原因写文档的人默认读者跟自己一样了解上下文省了设计说明。但一份设计文档的寿命往往比作者在项目组的时间长半年后新来的开发要能靠文档上手文字说明比图更关键。解决每张图配一段设计说明至少三百字写清楚为什么这么设计、有哪些取舍、如果需求变化这张图哪里要改。没有说明文字的图在评审时会被直接驳回。5.6 不按UML规范画图符号全靠个人习惯现象类图里的依赖箭头和关联箭头混用组合菱形画成了聚合状态图的初始状态点画成了圆圈评审专家指出符号不规范文档被要求返工。原因工具的限制或个人的随意习惯导致不规范的标注。很多画图工具的UML符号库不全有人就用近似符号代替结果图面意思完全变了。解决用PlantUML这类文本化工具时符号等价关系是明确定义的不会出现手动画图时「画得不太像」的问题。同时交付前用UML规范对照表自查一遍确认不需要的细节不要凭记忆去画箭头。6. 文档交付前的自检与验收三遍读图法一个实用动作评审前我习惯做三遍检查每遍只看一类内容不混合检查效率最高。第一遍只看关系所有类图的箭头方向、依赖方向、包图的依赖是否形成环。第二遍只看时序所有时序图的消息顺序是否和用例的基本流一致有没有漏掉备选流的分支。第三遍只对照代码挑三个核心场景跟着代码执行路径反向核对时序图和类图如果代码和数据文件不一致这可能是唯一的发现问题的入口。文档交付前还有一个实用动作把核心几类图都导出SVG而不是PNG。SVG格式在Word里缩放不模糊投屏评审时清晰度好任何一个细节放大都能看清。PlantUML 默认导出PNG加-tsvg参数即可输出SVG。这个习惯让我在评审现场免过好几次尴尬——被要求放大看某个关联关系的箭头时SVG放大后依然清晰PNG早就糊成一片了。最后提醒一个原则UML文档的价值在于设计决策的显性化。代码解决的是「怎么实现」UML文档解决的是「为什么这么实现」以及「哪些方案被否定了」。画图前先想清楚这两点——这套设计有哪些取舍、有什么明显的不能做的约束然后才落笔。把「不能做什么」写清楚比干巴巴贴一堆图更能帮到下一个接手代码的人。希望帮到你。本文还有配套的精品资源点击获取
返回列表