☰
UML网上订餐系统建模:需求模型、分析模型与用例实现全链路
2026/10/27 3:26:08 网站建设 项目流程

简介:这是一份面向软件工程课程学习者的UML建模实验报告,以网上订餐系统为案例,覆盖需求模型、分析模型与用例实现三个层面,适合正在完成UML大作业、课程设计或需要熟悉建模流程的学生参考。压缩包内共1个doc文件,约149KB,内容为一份完整的Word实验报告,便于直接阅读与摘录。该资源已有4229人学习下载。报告按游客、注册用户、管理员三类角色划分权限,给出注册、登录注销、餐品检索与订单管理等用例的事件流、前置与后置条件;分析模型部分梳理客户端、服务器、数据库与打印机的架构组成,列举orderlist、order、dish、user、guest等类的持久性与安全性机制,并附关键抽象关系、类图属性方法及注册、登录顺序图,可作为建模文档与图形表达的对照范本。

1. 一份 UML 网上订餐系统报告被退回两次:问题往往不在图画得好不好看

UML 网上订餐系统是软件工程课设、毕设里出镜率最高的题目之一,也是最容易被判成“图形正确、模型不通”的题目。带过几轮评审之后我发现,真正卡住人的从来不是用例图怎么画,而是三类角色、十二个用例、九个分析类和四个部署节点之间的对应关系有没有对齐:用例图里有的功能,类图里找不到承载它的类;顺序图里出现的消息,接口清单里查无此法。这份方案从需求模型一路推到分析模型、用例实现和答辩验收,每一步该产出什么、怎么自检都写清楚。适合正在赶建模大作业的人照着改,也适合要交一份需求分析文档的初级工程师拿去当模板。

2. 需求模型:三类角色、十二个用例与它们的边界归属

需求模型最容易写成功能罗列。把“注册、登录、浏览、下单”一条条抄下来,图很好看,但一到分析模型就接不上,因为用例没有边界、没有主参与者,也没有前置后置条件,后面的类图和顺序图就无从而来。这一章要做的事情是把角色收敛到三类,把用例收敛到十二个,然后给每个用例配一份能落地的规约。

2.1 角色收敛:游客、注册用户、管理员,以及被合并掉的经理

原始需求里出现了四类角色:游客、注册用户、管理员,还有一个“经理”。这里有一个坑:经理在需求模型里被提到,但翻遍用例实现,没有任何一个用例把经理作为主参与者写清楚,他只在对订单信息管理的描述里出现过一次“由管理员确认”。我的处理是把经理并入管理员,用“角色组”而不是“角色”来区分——管理员角色组下挂两个权限位:系统维护位和订单处理位。这样角色还是三类,权限却是四份。

角色可触发的用例明确不能碰的边界
游客 guest注册、餐品信息检索、查看部分留言、查看餐品评论、查看公告栏不能下单、不能收藏、不能评论、不能发留言
注册用户 user登录/注销、用户信息管理、收藏夹管理、餐品选购、餐品评论、订单信息管理(仅本人)、留言板留言不能管理餐品、不能查看他人订单
管理员 administrator后台登录、管理员餐品管理、订单信息管理(全部)、用户权限管理、公告栏管理、留言板维护不提供管理员注册入口,账号只能在数据库中添加

这张表的价值不在于好看,而在于它是后面所有权限判断的依据。比如“未登录的游客不会拥有收藏夹功能”这句话,在表里就体现为游客一行的边界,在代码里就体现为收藏接口的第一行校验。角色一旦收敛,用例的主参与者就不会出现“某个功能不知道归谁”的情况。

2.2 用例边界怎么切:购物车、收藏夹和订单是三件事

新手最容易把“餐品选购”“收藏夹管理”“订单信息管理”三件事揉成一个“购物车管理”用例,理由是它们都跟“买东西”有关。这样切会直接导致前置条件和后置条件写不清:购物车是会话态,刷新页面就该消失或者重建;订单是持久态,一旦生成就要落库并且可检索;收藏夹是长期意图,跟本次结算没有关系。

正确的切法是按数据生命周期切:

  • 餐品选购用例负责的是“当前订餐车”,它的后置条件是“订餐车内容发生变化,总价重新统计”,不产生任何持久化记录;
  • 收藏夹管理用例负责的是“用户与餐品之间的长期关系”,后置条件是“收藏记录增删成功”,与结算无关;
  • 订单信息管理用例负责的是“一次已经确认的交易”,前置条件明确写了“购物车内不能为空”,后置条件是“会员提交订单成功,管理员处理订单成功”。

这样切完之后,三个用例的核心类分别是 Cart(会话态,可以只存在内存)、Favorite(持久化)和 Order(持久化 + 状态机),类图里的关联也就自然对上了。同一个餐品可以同时出现在购物车、收藏夹和历史订单里,如果揉成一个用例,你就得在一个用例规约里解释三种不同的生命周期,评审时必然被追问。

还有一个边界要提前说清楚:餐品评论和留言板是两回事。评论挂在具体餐品下,谁都能看,登录用户能发能回复;留言板是系统级反馈,只有管理员能回复,长度不得少于 8 个字符。这两个功能在界面上长得像,在模型里必须是两个用例、两个类。

2.3 用例规约六件套:基本流、备选流、前置后置不能省

十二个用例,每个都要有六件套:简要说明、事件流(基本流 + 备选流)、特殊要求、前置条件、后置条件、扩展点。这份报告里每个用例的扩展点都写着“无”,这在评审时是会被问的——扩展点全为空,说明没有为可变点留设计余地,比如支付方式、配送方式这类将来可能扩展的地方。

备选流是最容易被误解的一节。很多人把备选流当成“出错处理”,其实它是另一条同样合理的路径。以注册用例为例,三条备选流的写法应该这样分:

  • 输入信息与系统校验不一致(字段长度超限、邮箱格式非法)——这是校验失败路径;
  • 用户名已被注册——这是业务规则冲突路径;
  • 系统异常无法注册(维护中)——这才是真正的异常路径。

三条路径的处理方式完全不同:第一条返回注册页并保留已填字段,第二条返回注册页并只清空用户名字段,第三条要给出可重试的提示并记录日志。写成一个“注册失败”就丢掉了设计信息。

再以餐品选购的备选流为例,原文列了七条,其中“用户未登录返回登录页”“购物车为空”“修改数量未改变”这三条属于完全不同的层次:第一条是权限前置条件不满足,第二条是业务状态非法,第三条是幂等操作。把它们的处理方式统一写成“给出提示”,实现阶段就得返工。

提示:每个用例的前置条件里,凡出现“必须是已登录会员”的,都要在用例实现顺序图的第一条消息里体现为一次会话校验,否则这条前置条件等于没写。

2.4 十二个用例的清单与主参与者对照

把需求模型落成一张表,是让评审一眼看懂系统范围的最快方式。这份报告的十二个用例可以这样整理:

编号用例名主参与者前置条件后置条件
UC01注册功能游客游客申请注册游客成为会员,默认已登录
UC02登录/注销注册用户、管理员已注册成功登录态建立或安全退出
UC03餐品信息检索游客、注册用户进入检索入口返回符合条件的餐品列表
UC04留言板管理注册用户、管理员用户已登录 / 管理员后台登录留言新增、回复或删除
UC05收藏夹管理注册用户已登录并选择收藏功能收藏记录增删成功
UC06餐品选购注册用户已登录且购物车非空(结算时)购物车内容与总价更新
UC07餐品评论注册用户、游客用户已登录(发表时)评论保存并可展示
UC08用户权限管理管理员管理员密码登录后台用户冻结/解冻状态变更
UC09用户信息管理注册用户已登录资料与密码修改完成
UC10公告栏管理管理员(发布)、所有人(查看)相应角色登录公告增删改查完成
UC11管理员餐品管理管理员管理员密码登录后台餐品新增、修改、删除完成
UC12订单信息管理注册用户、管理员购物车非空 / 管理员后台登录订单生成、发送、完成或撤销

这张表里有两个细节值得单独说。第一,UC08 用户权限管理和 UC09 用户信息管理名字很像,但主参与者完全不同,前者是管理员对别人的账号做冻结解冻,后者是用户对自己的资料做修改,绝不能合并成一个“用户管理”。第二,UC10 公告栏管理是一个主参与者写两个人,发布侧是管理员,查看侧是所有登录用户,这种“一端写两端读”的用例在后置条件里要分开描述,否则实现时会把查看权限也塞进管理员接口。

3. 分析模型:四层架构、七类分析机制与九个关键抽象

需求模型回答“系统做什么”,分析模型回答“系统由什么构成、这些东西各自扛什么责任”。这一步是整份报告的分水岭:做得细,后面的顺序图和类设计就是水到渠成;做得粗,类图就退化成一张属性清单。

3.1 架构模型:客户端、服务端、数据库与打印节点

架构模型给出的部署节点是四个:Client、Server、DBServer、Printer。很多人会把 Printer 当成客户端的附属设备,画在浏览器那一侧,这是个典型的翻车点。订单小票的打印发生在服务端确认订单之后,由服务端下发打印任务,客户端只拿到“打印成功/失败”的状态回执。如果画成浏览器直接调用打印机,那么换一台机器下单就打印不出来,而且打印失败会污染订单事务。

四层职责这样划分:

层承载节点职责不该出现的东西
表现层Client页面渲染、表单收集、结果展示业务规则判断、SQL
控制层Server参数校验、权限判断、事务编排直接拼 SQL
信息保存层Server实体持久化、事务边界、查询组装页面跳转逻辑
数据层DBServer表结构、索引、约束业务状态机
外设Printer打印小票、返回打印状态订单状态变更

这份报告里“信息保护层”这个叫法,实际上对应的是持久化和安全校验的组合,我在整理时会把它拆成两个明确职责:Repository 负责持久化,Guard 负责权限与数据校验。名字可以沿用原报告的叫法,但内部必须能说清这两件事是分开的。

3.2 分析机制:Persistency、Security、Distribution 怎么标到类上

分析机制是分析模型里最容易被忽略、也最能体现功底的一节。原报告给每个分析类标注了它承担的机制,整理出来是这样一张表:

分析类承担的机制落地方式
orderlist(购物车)Persistency、Security会话内存储 + 结算时校验归属
order(订单)Persistency、Security落库 + 状态机 + 只允许本人和管理员访问
dish(餐品)Persistency、Distribution落库 + 跨节点传输的价格快照
user(用户)Persistency、Redundancy落库 + 收货信息冗余存储
guest(游客)Persistency、Security仅会话标识,不落业务数据
favorite(收藏)Persistency、Communication落库 + 与餐品、用户双向关联
notice-board(公告栏)Persistency、Communication落库 + 一对多公告条目
comment(评论)Persistency、Parsing落库 + 内容长度与敏感词解析
system(系统控制)Persistency、Legacy Interface打印驱动对接、系统参数持久化

机制标注不是写给人看的装饰,它决定了类里要出什么方法。标注了 Security 的类,必须有一个校验入口;标注了 Persistency 的类,必须通过仓库出入口访问,不能到处 new。这一段可以直接落到代码契约上:

// Persistency 机制的落地点:业务实体只能通过仓库出入口访问,界面层拿不到连接 public interface OrderRepository { Order create(OrderDraft draft); // draft 由控制层组装,仓库只负责落库 Order findById(long orderNo); List<Order> findByUser(String userId, OrderStatus status); // 按状态 + 时间降序检索 void updateStatus(long orderNo, OrderStatus from, OrderStatus to); // 带前置状态校验 } // Security 机制的落地点:密码与安全问答分离存储,冻结只改状态不删记录 public interface UserGuard { boolean canLogin(String username, String rawPassword); // 内部做加盐比对 boolean canOperate(String userId, String targetUserId); // 本人或管理员才能操作 void freeze(String targetUserId, String reason); // 冻结后无法登录 }

前一个接口对应 Persistency,后一个对应 Security。参数说明一下:create接收的是已经组装好的订单草稿而不是散装参数,这样控制层改字段不会影响仓库;updateStatus必须带上源状态和目标状态,做乐观状态迁移,防止管理员和用户同时操作导致状态覆盖——这是并发场景下最常见的一类问题。freeze只做状态标记,因为冻结用户的历史订单和评论必须保留,删记录是红线。

3.3 关键抽象:九个类的属性、方法与职责清单

关键抽象是从需求里筛出来的、在系统生命周期内长期存在的实体。这份报告筛出九个:guest、comment、favorite、orderlist、system、order、dish、user、notice-board。逐个过一遍属性和方法,你会发现有些类名是多余的,有些属性放错了位置。

类核心属性核心方法职责说明
userusername、password、telephone、address、city、email、securityQuestionregister、login、updateProfile、changePassword账号与资料主体,冗余存收货信息
guestnameregister、browse未登录态的会话标识,只有行为没有数据
dishdishID、dishName、dishPrice、markPrice、meat、cooking、material、description、hot、recommendadd、modify、remove、search餐品主数据,价格分网订价与市场价
orderorderNo、time、foodName、foodNum、discount、itemsconfirm、send、complete、cancel一次交易,带状态机
orderlistusername、orderNumaddItem、removeItem、clear、calcTotal、checkout购物车,会话态,结算后转订单
favoriteusername、dishNameadd、remove、list用户与餐品的长期关系
commenttitle、content、name、telephonepost、reply、list餐品评论,带回复
notice-boardtitle、content、dish、activity、activityTimepublish、update、delete、list系统公告与餐品公告两类
systemusername、password、email、telephone、securityQuestionlogin、maintain后台控制与打印驱动对接

两处要改。第一,guest 类只有 name 一个属性,却挂了 register 和 browse 两个方法,实际上注册的输入全是 user 的字段,browse 的对象是 dish。我的做法是把 guest 降级为“未登录会话标识”,不参与业务关联,只在用例前置条件里出现;这样类图上就少了一坨没用的关联线。第二,order 里的 foodName、foodNum 这类字段,本质上是订单行的快照,应该单独抽一个 order-item 表达,否则一个订单只能存一道菜,扩展性直接锁死。

3.4 关联与多重性:0..* 和 0..1 不能随手写

类图上的多重性是评审最爱挑的地方,因为它直接决定表结构和查询写法。这份报告给出的关联里,有几处必须写清楚:

  • user 与 orderlist 是 1 对 0..*:一个用户只有一个当前购物车,购物车必须属于某个用户;
  • orderlist 与 order 是 1 对 0..*:一个购物车结算后可以产生多张历史订单,清空购物车不影响已生成订单;
  • order 与 dish 是 0..* 对 1:一张订单里有多道菜,但订单行必须快照菜名和单价,不能只存 dishID 外键;
  • favorite 与 dish、user 都是 0..* 对 1:收藏关系是用户和餐品之间的桥,桥两端都不能为空;
  • comment 与 user 是 0..* 对 1,与 dish 也是 0..* 对 1:评论必须同时挂人和挂菜,游客能看不代表游客能作为评论的拥有者。

最容易写反的是 order 与 user。写成 1 对 1,就等于一个用户一辈子只能下一单,后面的“订单按时间降序分类检索”“已完成订单与已撤销订单分状态查看”全部失效。另一个高发错误是把 dish 的删除设计成级联删除订单行——报告里明确写了“删除以后,对应的该餐品的订购记录仍然保留,方便日后查询”,这句话翻译成模型就是:dish 与 order 之间不做级联删除,订单行保存快照,dish 侧只做逻辑下架。

4. 用例实现:顺序图怎么画才经得起追问

用例实现是把用例规约翻译成对象交互的过程。这一章的核心是三个参与者的固定分工:界面、控制层、信息保存层。顺序图的 lifeline 控制在三条以内,消息编号连续,每条消息都能在类的方法清单里找到对应,这张图就立住了。

4.1 控制层与信息保存层的分工不能含糊

界面只负责收集和展示,控制层负责校验与编排,信息保存层负责落库。这个划分听起来像套话,但落到顺序图上区别极大。以注册为例,正确的消息序列是:

序号发送方接收方消息说明
1用户注册界面选择注册触发用例
2注册界面控制层submitRegister(form)表单整体提交,不是逐字段提交
3控制层控制层validate(form)字段长度、邮箱格式、必填项
4控制层信息保存层existsByUsername(username)查重,对应备选流 2
5控制层信息保存层saveUser(user)落库,密码加盐
6信息保存层控制层return userId返回主键
7控制层注册界面success(userId)默认已登录,跳首页

这套序列里有两个细节经常被画错。第一,查重必须走控制层发起,不能让界面直接查库,否则界面层就绑定了数据源。第二,注册成功后“默认已登录”意味着控制层还要写一次会话,这条消息很多人漏掉,导致用例规约里的后置条件对不上。

登录/注销同理,区别在于注销要显式清理会话,并且管理员注销后必须回到后台入口而不是前台首页。报告里那句“不提供管理员注册功能,管理员只能在数据库中添加”,在实现上体现为注册接口对角色字段做白名单,只允许写入普通用户角色。

4.2 餐品检索与订单结算的消息序列

检索用例看起来简单,实际上有一个容易翻车的点:检索条件要同时支持餐品名称和简介关键字,且返回结果里要带菜系、主要材料、做法描述、被订购次数、是否店长推荐。这意味着查询不是对 dish 单表的等值匹配,而是一次带聚合的查询。

-- 检索:名称或简介模糊匹配,同时带出订购次数与推荐标记 SELECT d.dish_id, d.dish_name, d.dish_price, d.mark_price, d.cooking, d.material, d.description, d.recommend, COALESCE(SUM(oi.num), 0) AS ordered_count -- 被订购次数由订单行聚合 FROM dish d LEFT JOIN order_item oi ON oi.dish_id = d.dish_id WHERE d.status = 1 -- 只查未下架餐品 AND (d.dish_name LIKE CONCAT('%', #{keyword}, '%') OR d.description LIKE CONCAT('%', #{keyword}, '%')) GROUP BY d.dish_id ORDER BY d.recommend DESC, ordered_count DESC;

参数只有两个:keyword是检索词,空串时退化为全量列表;status是上架状态,删除餐品用逻辑下架而不是物理删除,正是为了保住这张查询里的历史订单聚合。ORDER BY先按推荐位再按销量,是为了让店长推荐的餐品始终排在前面,这条排序规则要写进用例的特殊要求里,否则实现时容易被改成按价格排。

结算序列比检索长,因为它跨三个对象:购物车、订单、打印。消息顺序是:用户确认结算 → 控制层读取购物车并校验非空 → 控制层校验登录态与收货信息 → 信息保存层生成订单与订单行 → 控制层调用打印网关 → 返回订单号。打印放在事务之外,打印失败不回滚订单,只记录一条待补打记录——这是我在实际项目里踩过的坑,把打印放进事务里,打印机一卡纸订单就全部回滚,用户看到的是“下单失败”,实际上库存和优惠券已经动过了。

4.3 订单状态机:五种检索视图与四个真实状态

订单检索里列了五种类型:所有订单、待发订单、已发订单、已完成订单、已撤销订单。注意“所有订单”是一个视图,不是状态,真实状态只有四个。状态迁移必须带约束:

当前状态允许操作目标状态操作者约束
待发发送已发管理员必须填写送货人
待发撤销已撤销管理员或用户尚未发送才能撤销
已发确认收货已完成用户只能操作本人订单
已完成无——终态,只读
已撤销无——终态,记录保留不移除

这张表的价值在于它把“撤销”的时机卡死了:已经发货的订单不能被管理员撤销,只能走退货流程(本系统未建模,作为扩展点)。报告里写“撤消后的订单不会从系统的订单记录中移除,而是标记为已撤销”,这与表里的终态设计一致。实现时用带源状态的条件更新即可,不需要分布式锁。

4.4 从分析类到设计类的落地骨架

分析类只写领域行为,设计类才写技术细节。以订单结算为例,控制层的骨架大致是这样:

// 控制层:只做校验、编排和状态推进,不写 SQL,也不碰页面对象 public class OrderController { private final DishRepository dishRepo; private final OrderRepository orderRepo; private final PrinterGateway printer; public OrderResult checkout(String userId, List<CartItem> items, DeliveryInfo info) { if (userId == null) return OrderResult.fail("NOT_LOGIN"); // 前置条件:已登录会员 if (items == null || items.isEmpty()) return OrderResult.fail("CART_EMPTY"); // 备选流:购物车为空 if (info == null || info.getAddress() == null) return OrderResult.fail("NO_ADDRESS"); for (CartItem it : items) { Dish d = dishRepo.findById(it.getDishId()); if (d == null) return OrderResult.fail("DISH_OFF_SHELF"); // 餐品已下架 if (it.getNum() <= 0) return OrderResult.fail("BAD_NUM"); // 数量非法 } Order order = orderRepo.create(userId, items, info); // 落库并生成订单行快照 printer.printTicket(order); // 打印失败不影响订单 return OrderResult.ok(order.getOrderNo()); } }

参数三个:userId来自会话,不接受前端传入,防止越权下单;items是购物车条目,数量为 0 或负数直接拒绝,对应规约里“修改数量未改变则提示无更改”的幂等要求;info是收货信息,姓名、地址、电话三项必填。返回值统一用OrderResult包装,成功带订单号,失败带错误码,界面层只做文案映射。

配套的两张核心表:

CREATE TABLE dish_order ( -- order 是保留字,表名加前缀 order_no BIGINT PRIMARY KEY, user_id VARCHAR(32) NOT NULL, status TINYINT NOT NULL DEFAULT 0, -- 0待发 1已发 2已完成 3已撤销 address VARCHAR(255) NOT NULL, receiver VARCHAR(32) NOT NULL, telephone VARCHAR(20) NOT NULL, create_time DATETIME NOT NULL, INDEX idx_user_status (user_id, status, create_time) -- 支撑按用户+状态+时间降序检索 ); CREATE TABLE order_item ( id BIGINT AUTO_INCREMENT PRIMARY KEY, order_no BIGINT NOT NULL, dish_id BIGINT NOT NULL, dish_name VARCHAR(64) NOT NULL, -- 快照:餐品改名或下架后订单仍可读 unit_price DECIMAL(10,2) NOT NULL, -- 快照:下单时单价 num INT NOT NULL, UNIQUE KEY uk_order_dish (order_no, dish_id) );

两个设计点。第一,idx_user_status这个联合索引的顺序是 user_id、status、create_time,正好匹配“按状态分类检索并按生成时间降序”的查询模式,索引顺序换一下就变成全表扫。第二,order_item冗余了dish_name和unit_price,这就是分析模型里 Redundancy 机制的落地:餐品改价、下架、改名都不影响历史订单的展示与对账。

5. 避坑与排查:五处最容易被评审追问的建模细节

模型错不错,评审不一定当场看得出来;但下面这五处一旦出现,基本会被连问三轮。每一条我都按现象、原因、解决来拆。

5.1 登录被画成所有用例都 include 的公共用例

现象:用例图上十几条虚线全部指向“登录”,图面像蛛网,谁看都晕。原因:把公共行为当成了用例。用例是给参与者带来可观测价值的一组动作,登录本身不产生业务价值,它是其他用例的前置条件。解决:从用例图里删掉独立的登录用例,把“必须是已登录会员”写进各用例的前置条件;如果一定要体现会话,就单独画一张会话管理图,而不是塞进主用例图。注销可以保留,因为它有明确的会话终结语义。

5.2 类图画成属性清单,一个业务方法都没有

现象:九个类每个都挂着七八个属性,方法栏清一色 getX/setX,看不出这个系统能干什么。原因:把分析类当成了数据库表。解决:分析类的方法只写领域行为,比如 dish 的 add、modify、remove、search,order 的 confirm、send、complete、cancel,user 的 changePassword、updateProfile。getter/setter 属于设计类的实现细节,出现在分析模型里说明还没完成抽象。

5.3 顺序图把数据库画成一条生命线

现象:界面的箭头直接指向 DB,中间的控制层和信息保存层变成了转发器,图上出现 select * from 之类的消息名。原因:三层被压缩成两层半,控制层没有承担编排职责。解决:顺序图最多三条生命线——界面、控制层、信息保存层;数据访问是信息保存层的内部行为,不出现在消息箭头里。如果确实需要表达事务边界,在信息保存层自调用上标一笔即可。

5.4 多重性写反,一个用户只能下一单

现象:类图上 user 与 order 标成 1 对 1,或者 order 与 dish 标成 1 对 1。原因:照着“一个用户对应一条订单记录”的直觉写,没有考虑历史订单。解决:user 1 — 0..* order,一个用户可以有多张历史订单;order 0..* — 1 dish 是“每行一道菜”,整张订单与多道菜是通过订单行关联的。改多重性只是第一步,还要回头检查表结构和查询语句,因为多重性错的地方,索引基本也建错。

5.5 删除餐品时级联删掉了历史订单

现象:管理员删除下架餐品后,历史订单里的这道菜消失了,对账对不上。原因:外键设了 ON DELETE CASCADE,或者删除逻辑写成物理删除。解决:餐品只做逻辑下架(status 置 0),订单行冗余菜名和单价快照,外键不设级联删除。这条与需求里“删除以后对应的订购记录仍然保留”是直接对应的,改的时候顺手把这句写进用例的后置条件,评审一看就知道你想过。

注意:这五条里,第 5.2 和第 5.5 是“改起来最贵”的两条——前者影响整个类图的表达力,后者影响数据可追溯性,动手画图之前先把这两条确认一遍,比事后返工划算。

6. 验收与答辩:用十分钟证明这份 UML 模型能跑通

答辩现场最怕的不是被问细节,而是讲完十分钟,评委不知道你的模型能不能支撑一个真实系统。我的做法是把十分钟切成四段,每段绑定一种图形,形成一条闭环证据链。

第一段两分钟讲范围:只讲那张十二个用例的对照表,说清三类角色、十二个用例、哪些是后台专属。这一段的目标是让评委知道边界在哪,避免他后面问“为什么没有支付”。第二段三分钟讲结构:架构模型的四个节点加九个关键抽象,重点讲清楚 Printer 为什么在服务端、dish 与 order 之间为什么不级联删除。第三段三分钟讲一条完整链路,选注册或订单结算都行,从顺序图第一条消息讲到落库,中间穿插一句表结构里的索引和快照设计。第四段两分钟讲取舍:主动交代你没做的部分,比如退货、支付、多门店,以及为什么没做——这些是扩展点,不是遗漏。

自检的时候我会走一张三方对齐表,任何一个用例对不上就不提交:

检查项通过标准常见不通过表现
用例 → 类每个用例至少有一个承载类和一个控制入口检索用例找不到对应的查询方法
类 → 顺序图顺序图里出现的每条消息都是类的方法图上出现类图里没有的方法名
顺序图 → 表结构持久化消息都能落到具体表字段订单行没有价格快照字段
前置条件 → 校验每条前置条件在实现里有对应校验分支只写了“必须登录”但接口没校验

有一年我帮人看报告,图很漂亮,类图十九个类,顺序图画了十二张,结果一问“已发货的订单能不能撤销”,对方翻了半天说应该可以。这就是模型没有闭环——状态迁移约束从来没在任何一个图里出现过。从那以后我每次交建模作业前,都强制走一遍“随便挑一个状态,问它能不能变成另一个状态,从图里找依据”的流程,找不到依据就说明还缺一张状态图或者一段约束说明。

答辩前把这三件事做掉:把十二个用例的名字背熟(评委经常随机点一个让你讲),把九个类的职责用一句话说清,把订单状态机画在脑子里。真被问到答不上来的地方,直接说“这一块当前模型没覆盖,属于扩展点”,比硬编一个答案安全得多。

希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询