UML网上订餐系统建模全攻略:从用例图到状态机的避坑指南
简介一份UML网上订餐系统实验报告面向软件工程、系统分析与设计课程的学生适合作为UML建模大作业或课程设计的参考资料。内容以网上订餐系统为实际案例从需求建模、分析模型到用例实现逐步展开涵盖用户权限管理、注册功能、登录注销、餐品信息检索、订单维护等典型模块并配有需求模型、架构模型、关键抽象、分析机制、类图和顺序图等UML制品能够帮助读者理解用例图、类图、顺序图之间的联系与绘制规范。资源包内为1个doc文档约149KB文档结构清晰打开即可查看完整实验报告及图例。目前已有4200余人浏览学习认可度和参考价值较高。通过研读其中事件流、前置条件、后置条件等规范写法以及类设计与顺序图的具体实现可快速掌握UML建模在真实系统分析中的应用思路为独立完成系统建模报告提供方法论和模板支持。1 为什么一份 UML 网上订餐系统文档九成学生都栽在用例图上拿到“UML网上订餐系统.doc”这种题目多数人第一反应是去网上找模板下载一份文档改个名字就交。结果往往是被老师一句话怼回来“你的用例图里注册算用例还是算前置条件”这不是老师刁难而是说明这份文档的用例图没有经过业务逻辑推敲整份文档自然就站不住。UML 网上订餐系统的本质不是画出九种 UML 图而是用一套统一的建模语言把“顾客点餐、商家出餐、骑手配送、平台结算”这条业务链说清楚。适合谁做正在做课程设计、准备软考 UML 试题、或者第一次用 UML 做系统建模的计算机专业学生。这篇笔记按我实际交付这类文档的顺序来讲先把用例图立住再做静态和动态建模最后讲排版和答辩避坑。2 从用例图到活动图把点餐流程建模成一张能答辩的图2.1 用例图是门面参与者、用例、包含与扩展关系的选型用例图是整份文档里老师第一眼会看的图。它不负责表达“怎么做”只负责表达“谁”能对系统“做什么”。很多人的用例图翻车不是画得丑而是把用例的粒度搞错了。一个网上订餐系统最基本的参与者有三个顾客、商家、配送员。还有一个容易被忽略的——系统管理员他负责商家审核、订单仲裁、数据统计。不要画“用户登录系统”这种用例登录是几乎所有用例的公共前置条件应该放在用例的前置条件说明里而不是画成一个独立的孤岛用例。用例之间的关系常见的有 include包含和 extend扩展。我见过太多文档把这两种关系画反。记住一个判断标准如果用例 A 执行过程中必须执行 B那么 A 包含 B箭头从 A 指向 B例如“提交订单”必须包含“生成订单明细”和“支付结算”如果用例 A 在某个分支条件下才触发 B那么 A 扩展 B箭头从 B 指向 A例如“订单超时未支付”扩展“取消订单”这就是一种可选的异常分支。硬要较真的话网上订餐系统的订单状态流转用状态图表达更准确用例图的扩展关系更适合表达“可选功能分支”。下面给一个可以直接抄的用例图 PlantUML 脚本画完导出 PNG 放进文档。注意类图、用例图这些模型图我推荐用 PlantUML 或 StarUML 生成比 Visio 手画好维护得多。startuml left to right direction skinparam actorStyle awesome actor 顾客 as C actor 商家 as M actor 配送员 as D rectangle 网上订餐系统 { (浏览菜单) as UC1 (搜索菜品) as UC2 (加入购物车) as UC3 (提交订单) as UC4 (在线支付) as UC5 (订单评价) as UC6 (接单管理) as UC7 (订单配送) as UC8 (商家入驻审核) as UC9 C -- UC1 C -- UC2 C -- UC3 C -- UC4 C -- UC5 C -- UC6 M -- UC7 D -- UC8 UC4 . UC5 : include UC2 . UC1 : extend UC6 . UC4 : extend } enduml这段脚本的逻辑说明矩形框代表系统边界三个参与者分别站在边界外能直接访问的用例用实线箭头连接。include 关系在画图时用虚线箭头箭头上标注 方向从基用例指向被包含用例。extend 关系同样用虚线方向从扩展用例指向基用例。参数上要注意两点一是参与者一定要画在系统边界外部很多新手把参与者画进矩形里这在 UML 规范里是错的二是每个参与者至少关联两个用例否则这个参与者没有存在价值会被答辩老师追问“这个角色为什么单独存在”。2.2 活动图画业务流转泳道划分与分支条件的四个参数用例图画的是“能做什么”活动图画的是“怎么做”。网上订餐系统的核心业务是“从顾客下单到订单完成”的全过程这个过程跨了顾客、系统、商家、配送员四个主体用活动图表达最合适。活动图最关键的落地参数就四个泳道swimlane、初始节点、活动节点、判断节点。泳道按照参与主体划分每个泳道里只放该主体能执行的动作。判断节点必须写清条件比如“支付成功”这个判断条件两个出口分别标注“是”和“否”是就去商家接单否就回到待支付状态。还有一个容易漏的点——并发分叉。顾客支付成功后“通知商家备餐”和“通知配送员抢单”这两个活动是并发的中间要用一条水平粗线分叉汇合时再用一条粗线合并。你不画这个分叉老师会认为你对业务流程理解不到位。3 静态结构建模类图与对象图的边界、属性与关系命名3.1 类图的核心实体类、边界类、控制类怎么分类图是 UML 网上订餐系统文档里技术含量最高的一张图也是容易被看出“是不是抄的”的一张图。很多模板里的类图把所有类堆在一起没有分层。规范的做法是把类分成三层边界类界面与控制器的交互、控制类业务逻辑处理、实体类数据库中的持久化数据。以一个具体的订餐场景来拆。顾客点击“提交订单”按钮时前端页面是“订单界面”边界类后台处理请求的是“订单控制器”控制类控制器操作数据库里的“订单”、“订单明细”、“菜品”三个实体类。边界类命名用 OrderView、OrderController 这类后缀实体类直接叫 Order、OrderItem、Dish不要画一个巨大的类然后里面塞二十个属性控制类和实体类要分开否则数据库设计没法定。下面给一个类图的 PlantUML 示例包含关系命名startuml class User { -userId: int -userName: string -phone: string register() login() } class Order { -orderId: int -orderTime: datetime -totalPrice: double -status: OrderStatus createOrder() cancelOrder() payOrder() } class OrderItem { -itemId: int -quantity: int -price: double calcSubtotal() } class Dish { -dishId: int -name: string -price: double -stock: int updateStock() } User 1 -- 0..* Order : 创建 Order 1 -- 1..* OrderItem : 包含 OrderItem 0..* -- 1 Dish : 引用 enduml这个脚本里关系箭头的多重度是重点。User 到 Order 是 1 对 0..一个用户可以创建多个订单但一个订单必须属于一个用户。Order 到 OrderItem 是 1 对 1..一个订单至少要有一条明细不然订单金额没法计算。OrderItem 到 Dish 是 0..* 对 1因为一个菜品可以被多个订单明细引用而当菜品下架时历史订单明细仍然存在。3.2 对象图就画一个瞬间为何一个场景一张图对象图是类图的“快照”。它不画类画的是某个时刻对象之间的关联和属性值。很多同学的文档里根本没有对象图有的是把类图改了改类名就变成对象图属性值都不带这属于硬凑篇幅答辩时一提问就露馅。对象图的黄金法则是一个场景一张图。网上订餐系统里最有价值的对象图是“订单刚创建时”和“订单已完成时”两个时刻的快照。以“顾客张三提交了一个含两份鱼香肉丝订单”为例对象图里要画出一个 Order 对象属性 status 标注为“待支付”还要画两个 OrderItem 对象和一个 Dish 对象对象名格式是“对象名:类名”下面注明具体属性值。对象图的意义在于验证类图的多重度和属性设计是否合理。如果你发现一个对象图里出现了多个关联关系对不上回去改类图这是建模迭代的正常过程。3.3 关系命名与多重度约束的实际取舍关系命名是 UML 网上订餐系统文档里最容易被忽略的细节。类之间的连线不应该只是光秃秃的线线上要标注“创建”“包含”“引用”这类动词。命名动词要符合业务语义不要写“拥有”“关联”这种万金油。我见过一份文档User 和 Order 之间的关联线写的是“has”这能表达业务吗看的人会疑惑用户是拥有订单还是用户拥有订单记录改成“创建”就清晰了。多重度方面要特别注意“0..”和“1..”的区别。“0..*”表示一个用户可以不创建订单也能存在于系统但如果系统规则是“不注册不能点餐”那 User 存在的意义是什么如果一份文档里出现这种逻辑矛盾说明建模者没有理解系统规则。常见的做法是系统允许游客浏览菜单但只有注册用户才能下单所以在浏览菜单这个用例上关联游客在提交订单用例上关联注册用户。这个细节写进文档老师会认为你真的做过业务分析。4 动态行为建模时序图、状态图与构件/部署图的落地分工4.1 时序图画一次点餐流程生命线、消息与返回消息的七个要素时序图是老师判断“你是不是只会画结构图”的关键分水岭。网上订餐系统的时序图应该画“顾客提交订单”这个完整用例而不是画一个“用户登录”就完事。画时序图先设定一条垂直的生命线每个参与对象一条从上到下按时间顺序排列消息。能拿高分的一个技巧是一定要画返回消息。很多同学只画箭头从左到右系统内部对象之间的返回直接省略。不画返回消息的话调用关系就是断的例如“订单控制器调用支付服务”这个消息发出后必须画一条虚线箭头从右往左返回“支付结果”。PlantUML 里返回消息用虚线箭头箭头上写返回值。下面给一个标准的时序图脚本startuml actor 顾客 as C participant 订单界面 as OV participant 订单控制器 as OC participant 订单服务 as OS participant 支付平台 as PS C - OV : 点击提交订单 OV - OC : 提交订单请求 OC - OS : 校验菜品库存 OS -- OC : 库存充足 OC - PS : 发起支付请求 PS -- OC : 支付成功回执 OC - OS : 创建正式订单 OS -- OC : 订单创建成功 OC -- OV : 返回订单号 OV -- C : 显示支付成功页面 enduml4.2 状态图只画订单状态机状态、事件、动作与守卫条件状态图在一份网上订餐系统文档里专注画一个对象的状态变化就够订单。不要画用户状态也不要把菜品库存画成状态图。一个标准订单状态机包含待支付、已支付、备餐中、配送中、已完成、已取消、退款中这几个状态。每个状态之间的迁移必须由事件触发事件上标注守卫条件。例如“已支付”到“备餐中”的迁移触发事件是“商家确认接单”守卫条件是“支付结果成功”。还有一条容易出错的路径“待支付”到“已取消”触发事件是“用户主动取消”或“超时 15 分钟未支付”。这几条路径要齐不能只画主流程。画状态图时用 PlantUML 脚本会让文档的图统一风格。但要注意脚本里的箭头名称我见过把“Timeout”写成“TimeOut”被老师圈出来当成低级错误这类细节不用太紧张但能避免就避免。4.3 组件图与部署图给老师一个“可运行”的交代组件图和部署图往往是整份文档最薄的部分但恰恰是这两个图让老师觉得“这个系统真的能跑”。组件图表达系统的物理模块划分网上订餐系统的组件图一般分三层表现层用户 Web 端、商家 Web 端、配送 App 端、业务逻辑层订单组件、支付组件、菜品组件、用户组件、数据层关系型数据库、缓存。三个层之间用依赖关系箭头连接箭头从表现层指向业务层再从业务层指向数据层。部署图表达软件组件在硬件节点上的分布。常见画法是三台服务器节点一台部署前端应用服务器一台部署业务后端服务一台部署数据库服务。数据库节点要标注具体的数据库类型比如 MySQL不要只写“数据库”看不清技术栈的部署图等于没画。组件图和部署图之间有个衔接细节部署图里的每个节点要对应到组件图里的一个组件。如果你的组件图里有“订单组件”但部署图里没有任何节点提到它这就叫模型不一致。5 文档交付与答辩避坑从 doc 排版到 UML 图常见的 5 个翻车点5.1 现象与原因——五条血泪经验先说第一条用例图里的“游客”和“用户”混用。现象是描述用例时一会儿写“游客登录”一会儿写“用户下单”看的人不知道这两个是不是同一个角色。原因是用例建模前没有定好参与者列表。解决方法是文档开头先列出参与者清单注明游客未登录会话、注册用户已登录、商家、配送员、管理员五个角色后面所有图都沿用同一套命名。第二条类图属性类型与后续数据库表字段对不上。现象是类图里 User.userId 的数据类型是 string到了数据库设计章节变成了 int。原因是画类图和写数据库设计不是同一个人或者分两天写忘了对照。解决方法是把数据库表结构放在类图之后写每写一个表就回头核对一遍类图的属性类型这是建模一致性的最低要求。第三条时序图里没有返回消息。现象是整张图只有实线箭头从左到右从顾客到订单界面再到控制器再到数据库然后就结束了。原因是对时序图的理解停留在“谁调用谁”层面不知道每次调用都应该有返回。解决方法是逐一检查每条实线箭头必须配一条虚线返回箭头即使返回值是 void也要画一条标注 void 的虚线。第四条状态图的迁移条件只写状态不写事件。现象是“已支付”直接一个箭头指向“配送中”线下问老师怎么触发的答不上来。原因是把状态图当成了流程图状态图的核心不是状态列表而是“什么事件导致状态迁移”。解决方法是每条迁移箭头上必须写“事件[守卫条件]/动作”例如“骑手点击取货 / 订单状态已完成”。第五条文档里的 UML 图风格不统一。现象是前两张图是手绘风格后两张是 StarUML 导出配色和字体完全对不上。原因是图是一张一张从不同渠道凑的。解决方法是全部图都用同一个工具画PlantUML 脚本一次性生成风格统一后期改图也比改图片快得多。这条是纯经验之谈别不信。5.2 文档组织与答辩前自检清单一份能过查重、能顺利答辩的 UML 网上订餐系统文档结构顺序是这样的需求分析章节里的用例图然后是静态建模里的类图和对象图再是动态建模里的时序图、状态图、活动图最后是组件图和部署图。活动图不要放在需求分析之前因为活动图涉及具体业务分支应该放在用例图之后作为用例场景的补充说明。文档的 Word 排版有一个细节图片不要粘贴成位图。UML 图在 Word 里要可编辑要么粘贴矢量图要么在 Word 里用绘图画布重画。原因是答辩时老师会用放大镜看你的图位图一放大就糊矢量图放大多少倍都清晰这个印象分能差出一档。还有一个常被忽视的翻车点目录页的图表索引。给每张图配上编号和图题例如“图 3-2 订单状态图”正文里引用这张图时写“如图 3-2 所示”这是 UML 建模文档的标准章法没有图题索引的文档会被认为不专业而且自己答辩翻页时也方便定位相当于给自己准备了提示条。答辩前拿十分钟做一次自检对着用例图问自己每个用例对应的界面路径是什么对着类图问自己每个类的关键属性在数据库表里有没有对应字段对着时序图问自己返回消息的数据从哪里来这三个问题能回答上来基本就稳了。6 一个收尾技巧用订单状态机反向验证整套 UML 模型是否自洽把 UML 网上订餐系统文档全部画完之后别急着导成 PDF。花半小时做一件事用订单状态机去反向检验其他图这个习惯能让文档质量上一个台阶。做法很简单拿出一张纸把状态机的每一个迁移路径列出来然后逐条追问。拿“待支付”到“已取消”这条路径举例状态图里触发事件是“超时未支付”那么时序图里有没有画“定时任务扫描订单”这条消息如果没有说明时序图的场景覆盖不全补上。再看类图Order 类里有没有记录“下单时间”这个属性没有的话超时判断从哪里来补上。最后看部署图定时任务跑在哪个节点上如果部署图里根本没有任何节点提到定时器那就漏了一个组件。这就是状态机作为验证基准的价值。我自己的习惯是先把订单这条主链路在状态图里全部跑通再扩展到支付、退款、评价这些旁支。状态机能覆盖主链路其余的图自然能兜住百分之八十的完整性。每次带学生做这类课程设计我都会让他们做这个测试做完再交稿被老师中途打回来的次数明显变少。UML 建模就是这么个活——图不在多而在每张图都有一条能对上号的逻辑链。希望这份笔记里的方法和坑能帮到你祝你的订餐系统文档一次通过。本文还有配套的精品资源点击获取