简介:一份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 建模就是这么个活——图不在多,而在每张图都有一条能对上号的逻辑链。希望这份笔记里的方法和坑能帮到你,祝你的订餐系统文档一次通过。
本文还有配套的精品资源,点击获取