UML建模设计航空订票系统:从用例图到部署图全解析
2026/9/18 5:00:59 网站建设 项目流程

简介:这份PDF以航空订票系统为案例,系统讲解UML建模设计在软件工程中的应用,适合需要掌握用例图、类图、包图、顺序图、协作图、状态图、活动图、组件图与部署图的读者,也适用于课程设计或期末项目参考。内容覆盖新用户注册、登录验证、航班查询、机票预订与退票等核心业务,并通过用户、管理员与未登录用户三类角色展示权限与信用评价交互,帮助理解复杂系统如何拆解为可管理模块。资源为单个PDF文件,大小2.04MB,完整保留标注与图表,方便直接阅读或打印学习,已有1958人浏览学习。读者可从中学到从业务流程到九种UML图的完整建模思路,包括类继承关系、包依赖结构、对象交互顺序与状态迁移等关键设计要点,对撰写课程报告或实际系统设计均有参考价值。

1. UML建模设计航空订票系统,为什么值得拆开讲

一套完整的UML建模设计,放在航空订票系统这个场景里,通常不是画九张图那么简单。我拆过不少课程设计和项目初版方案,最常见的失败原因是:用例图画完就开始上手写代码,后来评审时发现类图和顺序图对不上,活动图没有处理并行分支,部署图忽略了协议说明。这份设计把未登录用户、已登录用户、管理员三类角色和外部信用评价系统都纳入了边界,并且把“月度退订两次降低信用等级、过低禁止购票”变成可校验的建模规则,适合拿来练习从需求捕获到物理部署的全流程。下面按我实际做UML设计时的顺序展开。

2. 用例图先行:把订票系统的角色、用例和边界钉死

2.1 从一句话场景梳理角色与权限边界

项目开头给出的情景读出来的关键信息是:未登录用户只能查询航班信息;已登录用户能购买、查看、退订;管理员负责安排航班;外部信用评价系统会在用户频繁退票时降级。画用例图第一步不是找用例,而是站在系统边界外找人。这里的人有三个:未登录用户、已登录用户、管理员。信用评价系统不是人,但它是外部参与者,因为它会发起“降低信用等级”的请求。

这套身份和权限设计有一个容易被忽略的点:登录验证支持客户和管理员两种方式,权限并不完全按“有没有登录”区分。素材里写得很清楚,客户登录后不能使用管理员界面,管理员登录后才能安排航班。也就是说,已登录用户这个概念在建模时应拆成“客户会话”和“管理员会话”,用例图里用角色继承来表现会更准确。简单处理时可以直接用三个角色,但要把“客户不能安排航班”写在用例描述的前置条件里。

2.2 包含、扩展与泛化关系什么时候用

用例图中,登录系统与购买机票、查看机票、退订机票之间是包含关系,用<<include>>表示。含义是:执行购买用例之前,必须经过登录用例。这和代码里的required参数类似,强调的是强依赖。购买机票与评价系统之间的关系是扩展关系,用<<extend>>表示。评价系统通过检索用户退票次数与时间,在满足“一个月内退订两次及以上”或“信用等级过低”时,把“禁止购买”追加到购买流程后面。这就是扩展关系典型用法:基础用例本身完整,扩展用例在特定条件下插入。

很多初学者把包含和扩展弄反。记住一条判断规则:如果基础用例不执行扩展也成立,就是扩展;如果不先做包含用例,基础用例根本走不下去,就是包含。用户查询航班不需要登录,所以查询用例和登录用例之间没有包含关系。购买机票必须登录,所以购买用例包含登录。

2.3 用例描述要写到评审能直接看

画图只是半成品,完整的用例建模必须配套用例描述。我一般用表格把每个用例的参与者、前置条件、基本流程和异常流程写清楚。下面以“购买机票”为例。

内容
用例名称购买机票
参与者已登录用户、外部信用评价系统
前置条件用户已登录;信用等级未低于禁止购买阈值
基本事件流1. 用户进入“我的航班”界面 2. 查询舱位、客机、航线、客户类型信息 3. 在下拉框选择票信息 4. 系统显示票务相关内容 5. 用户确认并提交订单 6. 系统写入机票数据库表
备选事件流2a. 未登录用户点击购买,系统跳转登录页面 4a. 信用评价系统检测到一个月内退订次数大于等于2,降低信用等级 6a. 信用等级过低,系统拦截并提示禁止购买
后置条件机票信息入库;订单状态更新;用户可查看已购机票

这段描述直接把素材里的功能细节和外部评价系统合并了。写用例描述时,事件流里的“用户点击查询”“显示内容”“添加数据库”要尽量用系统术语,但不要写界面控件名。下拉框、按钮属于实现细节,图里不画,描述里写清楚即可。

对应的用例图可以用 PlantUML 快速画出来,方便在评审前迭代,不用一上来就打开 Rational Rose 拖框。

@startuml left to right direction actor "未登录用户" as Guest actor "已登录用户" as User actor "管理员" as Admin actor "信用评价系统" as Credit rectangle "航空订票系统" { usecase "查询航班信息" as UC_Query usecase "登录系统" as UC_Login usecase "购买机票" as UC_Book usecase "查看已购机票" as UC_View usecase "退订机票" as UC_Return usecase "安排航班信息" as UC_Arrange usecase "禁止购买" as UC_Forbid } Guest --> UC_Query User --> UC_Login Admin --> UC_Arrange UC_Login ..> UC_Book : <<include>> UC_Login ..> UC_View : <<include>> UC_Login ..> UC_Return : <<include>> UC_Book ..> UC_Forbid : <<extend>> Credit --> UC_Forbid @enduml

这里<<include>>表示购买、查看、退订都必须先经过登录;<<extend>>表示购买流程在信用过低时扩展出“禁止购买”分支。信用评价系统作为外部参与者触发禁止购买,所以箭头指向扩展用例。注意 PlantUML 中..>是虚线,表示非强关联;-->是实线,表示直接发起。用例图不画实现细节,所以不要在里面出现“数据库表”或“下拉框”。

3. 类图与包图:静态建模要能落得下属性、方法和依赖

3.1 从用例里找候选类,而不是从表结构里找

用例图确定行为边界后,下一步是识别参与行为的实体和边界类。常见做法是照着用例描述里的名词抽:航班信息、已登录用户、未登录用户、管理员、评价系统、机票。素材里的类图把这些归纳成订票系统、已登录用户、未登录用户、管理员、评价系统。属性也好记:订票系统维护航班信息和 class;已登录用户有姓名、身份证、电话,操作有权限、预定、撤销、查看;未登录用户只有姓名,操作只有查看;管理员有姓名和管理员密码,操作是安排航班信息。

不要一开始就对着数据库设计表。类图关注的是职责分配,字段和方法的粒度要能支撑用例事件流。例如“查看已购机票”需要已登录用户有“查看”操作,“退订机票”需要用户有“撤销”操作,“安排航班信息”需要管理员有“安排航班”操作。如果后台再要加一个“信用等级”字段,应该放到评价系统依赖的类里,而不是塞给用户类。

3.2 类图的继承与依赖关系怎么画

素材里明确说订票系统是父类,已登录用户、未登录用户、管理员是子类,子类继承父类的属性和操作。这个设计在实际项目里会变成:用户这个抽象基类提供公共属性(姓名、身份证、电话)和公共操作(查看、预定、撤销),管理员在基础上加管理员密码和安排航班操作,未登录用户则被限制为只能查看。用代码骨架表达会更直观:

public class TicketSystem { protected String flightClass; protected FlightInfo flightInfo; public void view() {} } public class LoggedInUser extends TicketSystem { private String name; private String idCard; private String phone; public void authorize() {} public void book() {} public void withdraw() {} public void view() {} } public class Guest extends TicketSystem { private String name; @Override public void view() {} } public class Admin extends TicketSystem { private String name; private String adminPassword; public void arrangeFlight() {} } public class CreditSystem { public int getReturnCount(int userId) {} public void lowerCreditLevel(int userId) {} }

这里TicketSystem是父类,但把LoggedInUserGuestAdmin都直接继承它,会造成“未登录用户继承订票系统”的语义问题。实际建模课上可以这样交作业,生产系统更合理的做法是User为基类,Admin继承User,订单类单独存在。素材的父类叫订票系统,是课程设计里常见的简化方式,评审时要点出这个继承层次不严谨的地方。CreditSystem不必继承TicketSystem,它与用户之间是依赖关系,因为评价系统要检索用户退票次数。

3.3 包图:把类按依赖方向收拢

包图的作用不是把类图标进圆角矩形就完事,而是要对类进行组合,表示逻辑上的集合。素材里的包图把业务与用户、管理员、购买业务放在一起,并让它们与信用评价产生依赖关系。拆包时我一般遵守两个原则:第一,高层包不要依赖低层包的具体实现;第二,包与包之间不能出现环。这个系统可以分成六个逻辑包:用户包、管理员包、航班信息包、订单包、评价系统包、数据库访问包。购买业务包同时依赖用户和评价系统,评价系统依赖订单数据统计退票次数。

下面用 PlantUML 简单表示包依赖:

@startuml package "用户管理" as user_pkg { class User } package "航班管理" as flight_pkg { class Flight class Route } package "订单管理" as order_pkg { class Order } package "信用评价" as credit_pkg { class CreditEvaluator } user_pkg ..> order_pkg : 创建订单 order_pkg ..> credit_pkg : 统计退票次数 flight_pkg ..> order_pkg : 引用航班 credit_pkg ..> user_pkg : 降低信用等级 @enduml

虚线带箭头的依赖表示一个包需要知道另一个包的存在。订单包引用航班,信用评价包引用用户包,用户包又创建订单,这三个如果画成实线关联就容易出现循环依赖。实际建模时,我会在类图上把“用户创建订单”和“订单包含用户”收敛成单向关联:由用户包指向订单包,订单包不反向引用用户,而是通过订单项持有用户ID值对象。

3.4 用Visio画UML类图的常见坑

有人习惯用 Visio 代替 Rational Rose 画 UML 类图。Visio 的“UML Model Diagram”模板确实可以拖出类形状,右键添加属性和操作,但它不维护模型一致性。你在类图里改了方法名,顺序图里的同名消息不会自动更新。我的建议是用 PlantUML 或 StarUML 做源文件管理,Visio 只用来出最终交付图。如果你一定要用 Visio,把类之间的继承箭头、依赖箭头区分清楚:泛化用空心三角实线,依赖用带箭头的虚线。Visio 自带的三条线容易被拖散,画完记得锁定端点。

4. 动态行为建模:顺序图、协作图、状态图和活动图怎么联动

4.1 顺序图与协作图:同一交互要回答两个不同问题

素材里合作图和顺序图都描述了用户登录后购票的过程。顺序图强调消息按时间排列:用户先输入账号密码,系统验证后读取个人信息,服务器反馈验证,用户购票,数据库更新,最后显示金额。协作图则把对象放在几何位置上,用带编号的箭头表示消息顺序,不关心时间线,只关心谁和谁之间有交互。这就是为什么一个系统两边要各画一张图:顺序图用来检查消息顺序是否有遗漏,协作图用来检查对象之间是否实现了直接或间接通信。

以“用户登录并购买机票”为例,顺序图可以用 PlantUML 快速表达:

@startuml actor 用户 participant "登录界面" as Login participant "订票系统" as System participant "购买系统" as Booking participant "评价系统" as Credit participant "数据库" as DB 用户 -> Login: 输入账号密码 Login -> System: 提交登录信息 System -> DB: 校验用户 DB --> System: 用户信息 System --> Login: 登录结果 用户 -> System: 请求购买 System -> Booking: 创建订单 Booking -> Credit: 查询退票次数 Credit --> Booking: 信用等级 Booking -> DB: 插入机票记录 DB --> Booking: 写入结果 Booking --> 用户: 显示金额与账户信息 @enduml

顺序图里的每一条消息都要落在类图的操作上。比如“查询退票次数”对应CreditSystem.getReturnCount(int userId),“插入机票记录”对应订单类的持久化方法。如果消息名在类图里找不到对应的方法,说明类和交互是脱节的。评审时我会拿顺序图和类图对着看,这是最耗时间但最有效的一步。

4.2 状态图:识别生命周期不只有一个状态

素材里说系统有 7 种状态:未登录、注册、已登录、管理员登录、安排航班、评价、购买。状态图适合描述一个对象跨多个阶段的行为,这里其实是“用户会话”的状态。从初始状态开始,未登录用户通过注册或登录进入已登录状态;管理员登录进入管理员会话状态,可以继续安排航班;已登录用户必须经过信用评价系统评价后才进入可购买状态;购买后又可能因为退票被降级,回到不可购状态。

下面给一个简化的状态图:

@startuml [*] --> 未登录 未登录 --> 已登录 : 注册成功/登录成功 未登录 --> 已登录 : 管理员登录成功 已登录 --> 评价中 : 发起购买 评价中 --> 可购买 : 信用等级正常 评价中 --> 禁止购买 : 月度退票≥2次或信用过低 禁止购买 --> 可购买 : 信用等级恢复 可购买 --> 已登录 : 退票/查看 已登录 --> [*] : 退出登录 @enduml

状态图最容易出错的地方是漏掉派生状态。很多人只画“已登录”和“已退出”,却忘记信用评价会导致“可购买”和“禁止购买”两种子状态。素材里提到的信用评价系统交互,本质上就是状态机的迁移条件。不要把判断逻辑只写在活动图里,状态图里也要把触发迁移的事件明确标出来。

4.3 活动图:并行分支和汇合要配对出现

活动图常用于业务流程。素材里有两个活动图:一个是订票系统用户登录,一个是退票系统;还有描述管理员登录的操作。登录活动图非常典型:用户填完身份信息后发送验证码,判断是否收到验证码,收到则验证;没有收到则出现并行分支,可以取消发送并结束,也可以重新发送验证码再次验证。并行分支的画法需要用分叉和汇合,不能画成两个任意并列的菱形判断。

@startuml start :填写身份信息; :发送验证码; if (接收到验证码?) then (是) :填写验证码; if (验证成功?) then (是) :成功登录; stop else (否) :重新发送验证码; endif else (否) fork :取消发送验证码; :取消登录; stop fork again :重新发送验证码; :身份验证; if (验证成功?) then (是) :成功登录; stop else (否) :结束; stop endif endfork endif stop @enduml

这个活动图把“取消发送”和“重新发送”画成了并行分支,实际业务是二选一,用并行分支表达并不准确。更合理的做法是用决策节点:收到验证码走验证,没收到走重新发送或取消。素材里写的是“并行事件”,可能是当时的教学简化。我在评图时会把它改成决策节点,因为并行分支意味着两条路径会同时执行,而取消和重发不会同时发生。这就是为什么活动图一定要检查分叉和汇合的逻辑。

图种关注点评审要点
顺序图消息时间顺序消息是否对应类操作
协作图对象角色与链交互角色是否遗漏
状态图生命周期状态与事件初始/终止状态是否完整
活动图流程分支与并行分叉汇合是否配对

5. 组件图与部署图:把模型映射到可交付的物理架构

5.1 组件图:模块的依赖与接口

素材里的组件图把系统分成客户端程序、管理员程序、服务器端程序、数据库端程序、数据库五个部分。客户端和管理员端依赖服务器端,数据库端依赖数据库,服务器端通过一个接口连接到数据库端。组件图里的组件是实际文件,不是包。客户端程序对应可执行程序,数据库端程序对应数据访问层,数据库是运行时资源。

下面用一个 PlantUML 组件图表达:

@startuml component "客户端程序" as Client component "管理员程序" as Admin component "服务器端程序" as Server component "数据库端程序" as DBModule database "数据库" as DB Client --> Server : HTTP Admin --> Server : HTTP Server --> DBModule : 业务调用 DBModule --> DB : ADO/SQL @enduml

画组件图时,依赖箭头两端的组件要区分“编译期依赖”和“运行期使用”。客户端通过 HTTP 调用服务器端,这是运行期依赖,在部署图里表现为网络连接;服务器端通过接口调用数据库端,这里可以在接口处标注“数据库访问接口”。如果组件图里漏掉数据库这个实际文件,部署图里的数据库节点就会失去承载对象。

5.2 部署图:节点、协议与物理边界

部署图描述硬件节点和软件部署位置。素材给的设计是四部分处理器:用户端、管理员端、服务器端、数据库。用户端和管理员端通过 HTTP 与服务器端相连,服务器端通过 ADO 与数据库相连。部署图里除了节点,还要标出通信协议。HTTP 是应用层协议,ADO 是数据访问接口,还不完全是链路层协议。如果项目改成 Spring Boot 架构,这就是浏览器/客户端通过 HTTP 访问 REST 服务,服务层通过 JDBC 或 JPA 连 MySQL。同样是部署图,把协议从 ADO 换成 JDBC,会影响数据库端程序的组件选择。

5.3 建模评审清单:从这套设计里抽出来的可复用技巧

最后分享一个我常用的建模评审清单,每条都是从这套航空订票系统里抽出来的。

  • 用例图检查点:每个角色至少发起一个用例;外部系统必须作为参与者出现;包含和扩展关系不能反。
  • 类图检查点:父类与子类的关系是否符合语义;依赖关系是否指向对方的具体实现;属性是否覆盖用例描述中的信息。
  • 包图检查点:包之间是否有环;包依赖是否只发生在接口层。
  • 顺序图检查点:消息名在类图中是否能找到对应方法;返回消息是否完整。
  • 状态图检查点:是否有初始和终止状态;同一个事件是否触发多个无关联状态。
  • 活动图检查点:并行分支是否有对应汇合;判断节点的条件是否完备。
  • 组件图检查点:组件是否实际存在依赖;数据库端程序与数据库是否分离。
  • 部署图检查点:节点之间的协议是否明确;数据库是否单独成节点。

把这几点做成 Checkbox 清单,每次画完图照着过一遍。比如在顺序图里找到“查询退票次数”,回到类图里看CreditSystem有没有getReturnCount方法,没有就补;在状态图里看到“禁止购买”,回到用例图里确认存在对应的扩展用例。这样一整套 UML 建模设计航空订票系统,才能从交作业的图集变成能指导编码的设计文档。

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

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

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

立即咨询