简介:一份以简易教学管理系统为实践项目的UML面向对象分析与设计大作业文档,面向计算机、软件工程等相关专业学生,特别适合需要完成UML课程设计、掌握Rational Rose建模流程或进行面向对象分析设计的读者。文档为docx格式,整体共1个文件,压缩包大小约3.44MB,目前已有185人学习下载。内容完整覆盖课程设计目的、理论基础、设计内容与步骤,并给出了详细的需求陈述。系统围绕选课管理和成绩管理两大模块,包括课程表录入与生成、学生选课注册、课程信息查询、成绩录入与查询、成绩统计与报表生成等功能。文中按建模流程绘制了顶层用例图、选课管理用例图、成绩管理用例图、顺序图、类图、包图、状态图、活动图与组件图等,模型层次清晰,便于学习者对照参考。文档还包含设计任务分解和项目要求,能帮助读者理解UML概念、结构、语义,并熟练使用Rational Rose完成软件系统的分析与设计,也可供同类教学管理系统的开发借鉴。
1. 一份UML面向对象分析与设计文档,解决的从来不是画图问题
手头这份UML面向对象分析与设计讲义(.docx 文档),是不少软考中级备考者和一线开发反复翻的资料。它讲的是从需求到代码之间那条最常被跳过的路:先建用例模型,再抽候选类,接着画动态图验证流程,最后落成可评审、可追踪到代码的类图。UML 这套符号系统最大的价值不是图好看,而是让分析和设计有据可查、有责可追。适合谁读?准备软考中级 UML 建模的考生、正在写设计文档却担心画错的开发,以及想在团队里建立建模规范的架构师。读完你会得到一条能照着走的落地路径,外加六个画图时最容易翻车的细节。
2. 面向对象分析(OOA):从用例图到领域模型的落地顺序
在动笔画任何图之前,先明确一件事:分析阶段回答「系统要做什么」,设计阶段才回答「系统怎么做」。很多人拿到需求直接开画类图,跳过用例模型,结果类图和需求对不上,返工成本全压在后期。标准的 OOA 落地顺序是:用例图 → 用例描述 → 序列图/活动图 → 分析类图。下面按这个顺序逐层拆解。
2.1 用例图先画什么:参与者与用例的边界划分
用例图只有三样东西:参与者、用例、关系。参与者叫 Actor,画成火柴人,代表与系统交互的外部角色。第一个高频踩坑点是角色数量爆炸:把「管理员」「财务人员」「普通用户」全列出来,一张图十几个火柴人。判断标准是看对系统的操作目标是否本质不同,如果目标相同只是权限不同,那就是同一个参与者的不同权限,不是多个参与者。
用例用椭圆表示,命名用动词短语。《用户下单》《生成对账单》《执行退款》都是用例。常见翻车是把功能模块当成用例:「订单管理」「用户管理」不是用例,因为「管理」不是单一完整业务目标,它背后藏着一堆子功能。用例之间只有三种关系:
- include:基用例必定调用子用例。例如《下单》必定包含《校验库存》。
- extend:基用例在特定条件下才扩展。例如《下单》在支付失败时扩展《处理支付异常》。
- 泛化:用例或参与者之间的继承关系。
分析阶段的交付物不只是用例图,还必须有一份用例描述。图是索引,描述才是分析本体。建议每个关键用例配一张表格:参与者、前置条件、主成功场景(编号步骤)、扩展场景、后置条件。主成功场景写 4 到 8 步,每步一个完整业务动作,不写界面细节。这一步做扎实了,后面所有类的方法都有了出处。
2.2 类图是分析阶段的核心产物:属性与方法怎么定
分析类图不画界面,画的是系统内部的概念。最稳妥的方法是把用例描述拿来做文本分析:名词大概率是候选类,动词短语大概率是候选方法。比如「用户提交订单,订单包含多个订单项,系统根据库存判断是否出货」,这句话里《订单》《订单项》《库存》是候选类,《提交》《判断》是候选方法。把候选项收进一张表,去掉重复项和没有业务含义的词,初步类图就出来了。
分析阶段的类分成三类:边界类、控制类、实体类。这是 UML 分析与设计里的经典分法,也是软考 UML 建模的高频考点。边界类负责与外部交互,比如 Controller、对外接口;控制类负责业务流程编排,比如 OrderService;实体类是业务数据,比如 Order。分析阶段画类图时,属性和方法只写名字,不写类型、不做可见性标注。写类型是设计阶段的事,分析阶段写太细反而把后续设计绑死了。
属性从名词短语中的状态信息里抽:订单有编号、金额、状态,这是属性不是类。方法从用例描述里的动词抽:订单有提交、支付、取消。如果一个方法只在单个类内部使用,先不画进分析类图,等序列图画完再补回来。
2.3 动态结构图:序列图与活动图在分析阶段的分工
UML 里的动态结构图包括四种:状态图、序列图(时序图)、活动图、通信图(协作图)。软考中级经常直接问「动态结构图包括哪些」,答这四种就不会丢分。分析阶段用得最多的是序列图和活动图,分工很明确:序列图画对象之间按时间顺序的消息传递,活动图画业务流程里的分支与并发。
我一般建议先画序列图,再返修类图。做法是拿用例描述的主成功场景,逐行转成一条消息。比如「用户提交订单」变成 用户 → OrderController: submit(order),「系统校验库存」变成 OrderController → StockService: checkStock(items)。序列图的生命线就是候选类,消息就是候选方法。把序列图回贴到类图里,类的方法列表就完整了,而且每条方法都能追溯到具体用例步骤,这正是评审时最有说服力的部分。
活动图用来处理用例里的分支和并发:主成功场景里出现「支付成功走 A 流程,支付失败走 B 流程」,就值得画一张活动图把分支理清,再回头画序列图。状态图在分析阶段不必给所有类都画,只对状态复杂、生命周期明显的类画,比如订单状态、设备状态。订单从待支付到已支付再到已发货,这种迁移用状态图比在类图里堆一堆状态枚举清晰得多。
3. 面向对象设计(OOD):把分析模型变成可实现的类图
分析模型回答「有什么」,设计模型回答「怎么实现」。从 OOA 到 OOD 不是重画一遍图,而是把分析类图里的名字补全成可编码的细节:属性加类型和可见性,方法加签名,类与类之间的依赖关系落到接口和分层上。设计阶段的核心产物是设计类图和包图,再往后才是代码。
3.1 从分析类到设计类:属性类型、方法签名与可见性
设计类图要和代码几乎一一对应。属性要写全:可见性(+ 公开、- 私有、# 保护)、类型、默认值。方法要写返回类型和参数列表,比如 +submit(order: Order): boolean。分析阶段故意不写的细节,这里全部补上。补的时候守住一个原则:先定接口再定实现。不要在类图上直接写方法体,先定签名,方法体是代码阶段的事。
三类分析类在 OOD 阶段各有落点:边界类演化为 Controller、REST 接口;控制类演化为 Service 类,负责业务规则和事务;实体类演化为数据模型或持久化对象。三层架构里,Controller 依赖 Service,Service 依赖 Repository,实体类作为参数在层间传递。这个依赖方向必须在类图上画清楚,否则代码评审时会出现 Service 直接反向依赖 Controller 的循环引用,类图上一眼就能看穿。
设计阶段的包图也要开始画:一个包一个职责,包之间只允许从上往下依赖。如果一个 Service 同时依赖了多个底层数据源,包图会非常直观地暴露耦合问题。设计类图建议每张不超过 15 个类,再大就按模块拆成多张图,保证评审时一张图在一个屏幕里看得完,讨论才有效率。
3.2 设计原则在类图上的落点:依赖倒置与接口隔离怎么画出来
SOLID 虽然是代码层面的原则,在类图上却能直接检验。单一职责:一个类只应被一个修改理由所触发,对应到类图上就是一个类的入度依赖来源单一,方法列表聚焦一个业务主题。开闭原则:对扩展开放、对修改关闭,对应设计类图里把业务变化点抽象成接口。
依赖倒置是类图上最容易操作的一条:高层模块不要依赖低层模块,两者都依赖抽象。画法很直观——Service 依赖的是一个 PaymentGateway 接口,而不是具体的 WechatPay 或 Alipay。接口画在类图上方,实现类在下方,依赖箭头从 Service 指向接口(虚线箭头),实现类用实线空心三角接到接口上。只要依赖箭头不再指向具体实现类,这一条就落对了。
接口隔离的落点是看接口里的方法有没有被它的所有实现类用到。如果一个接口有八个方法,其中三个只有某一个实现类在用,这就是胖接口,类图上应该拆成两个接口。检查方法很笨但有效:对每个接口列出所有实现类,逐个核对方法使用率,出现大面积不用的方法就拆,不用犹豫。
3.3 23种UML设计模式的类图特征:模式不是背出来的
23种UML设计模式及其代码是很多人学 OOD 时的拦路虎。模式本身是从类图里总结出来的结构套路,不是背概念就能用的。正确的看图方式是抓类图结构:创建型模式解决「对象怎么创建」,结构型模式解决「类和对象怎么组合」,行为型模式解决「方法和消息怎么分发」。
创建型里单例的类图特征最明确:构造方法私有、类持有自己的静态唯一实例、getInstance 公开方法。工厂方法和抽象工厂的差别在类图上就是一层:工厂方法模式里创建逻辑由子类实现,抽象工厂模式则是一组产品族创建接口的集合,画出来后者的接口数量明显更多。
结构型里适配器的类图特征是目标接口、适配器、被适配类三者的关系:适配器实现目标接口,同时把被适配类组合进自己内部。装饰器则是接口加具体组件加装饰器抽象,装饰器持有接口引用。两者类图结构很像,区分点是适配器要转接接口,装饰器要增强方法,类图里装饰器有一条指向接口的依赖,适配器则多一条指向被适配类的实线关联。
行为型里策略模式的类图特征是上下文类持有策略接口,具体策略类各自实现算法。模板方法则把公共算法写在抽象类里,变化步骤作为抽象方法交给子类实现。画法上,策略模式用组合和依赖,模板方法用继承。我在设计评审里判断一个模式用得对不对,从不看名字,只看类图结构是否匹配这些特征。结构对,名字才有意义。用 PlantUML 描述一个策略模式类图,可以直接抄到本地跑通:
@startuml ' 策略模式:Context 持有策略接口,运行时切换算法 class OrderService { - strategy: DiscountStrategy + calculatePrice(amount: double): double } interface DiscountStrategy { + discount(amount: double): double } class NoDiscount class MemberDiscount { + discount(amount: double): double } OrderService o--> DiscountStrategy NoDiscount ..|> DiscountStrategy MemberDiscount ..|> DiscountStrategy @enduml上面脚本里o-->是聚合关系,表示 OrderService 长期持有策略接口;..|>是实现关系,两个实现类接到接口上。这个结构同时满足了开闭原则:新增一种折扣方式,只加一个实现类,不改 OrderService。评审时拿这个结构对照业务,比背模式定义有用得多。
4. 类图箭头含义与关系强度:一张表说清依赖、关联、聚合、组合
类图画得好不好,一半看箭头画得对不对。uml类图箭头含义是软考和日常评审里被问得最多的点,也是翻车重灾区:关系画反、菱形画错、虚线和实线不分。箭头不只是画法问题,每一个箭头都对应代码里的一种实现,画错图,代码评审必然吵起来。
4.1 六种关系的箭头画法与代码对应
关系分六种:依赖、关联、聚合、组合、泛化、实现。记忆可以从强度排序:依赖最弱,关联次之,聚合是「整体-部分」的弱拥有关系,组合是「整体-部分」的强拥有关系,泛化和实现属于类型层面的关系。下表直接可抄:
| 关系 | 图形符号 | 箭头方向 | 代码对应 | 强度 |
|---|---|---|---|---|
| 依赖 | 虚线箭头(---->) | 指向被依赖方 | 方法参数、局部变量、返回值 | 最弱 |
| 关联 | 实线 | 可带箭头,指向被持有方 | 成员变量持有对方引用 | 强于依赖 |
| 聚合 | 空心菱形 + 实线 | 菱形在整体端 | 整体持有部分的成员变量,部分可独立创建和销毁 | 弱拥有 |
| 组合 | 实心菱形 + 实线 | 菱形在整体端 | 整体创建并销毁部分 | 强拥有 |
| 泛化 | 空心三角 + 实线 | 三角指向父类 | 继承 extends | 类型关系 |
| 实现 | 空心三角 + 虚线 | 三角指向接口 | implements | 类型关系 |
依赖和关联的区别是高频考点:依赖只在某个方法调用时存在,关联是长期持有的引用。代码里一个类是另一个类的方法参数,那是依赖;一个类声明了另一个类的成员变量,那是关联。把方法参数全部画成关联,是类图画废的高发原因。
4.2 关系的多重性与导航方向:泛化、实现之外的隐藏信息
除了箭头,类图两端还要写多重性:1、0..1、0..、、1..。1 表示必有一个,0..表示零到多个,1..* 表示至少一个。多重性写在关系的两端,表示这一端可以同时存在几个对象。例如「订单 1 —— 0..* 订单项」,读作一个订单包含零到多个订单项;「账户 1 —— 1..* 卡」,表示一个账户下至少绑定一张卡。
导航方向是另一个容易画错的地方。带箭头的一端表示该方向可导航,也就是代码里持有对方的引用;没箭头的一端不持有引用,只能通过查询获得。很多人在类图上画线不画箭头,等于放弃了导航语义,到写代码时两边的类都互相写了引用,结果变成双向耦合。我的习惯是:每条关联至少一端带箭头,明确表示运行时谁持有谁。
多重性和导航方向在评审里价值很大:一眼就能看出接口应该长在哪边。如果一个类在多重性的「多」端持有「一」端的强引用,大概率导航画反了,改成查询更合理。
4.3 动态结构图包括哪些:状态图、活动图、序列图、通信图的选用
类图描述静态结构,动态结构图描述行为与交互。UML 中的动态结构图包括状态图、序列图、活动图、通信图这四种。它们关注点完全不同,选错图比画错箭头更让人头疼。
- 状态图:一个对象的生命周期状态迁移。元素是状态、事件、警戒条件。
- 活动图:业务流程的任务流,强调分支、并发、汇合。
- 序列图:多个对象按时间顺序的消息传递,强调先后。
- 通信图:与序列图表达内容等价,但强调对象间的连接关系而非时间。
实践里的选图诀窍:要展示一条业务路径,用序列图;要梳理分支和并发,用活动图;要定义对象合法状态和触发事件,用状态图;要讨论对象间的静态连接,用通信图。软考中级里经常给一段场景让补全序列图消息或状态图状态,先判断题目说的是「单个对象的状态变化」还是「多个对象的交互」,基本就不会选错图。
5. 软考UML建模与日常设计中的避坑清单:六个画图翻车教训
这一章把最常见的踩坑按「现象 → 原因 → 解决」列出来。前两类是逻辑问题,中间两类是关系符号问题,后面两类是工具和考试问题,逐条对照着查自己的图最有效。
5.1 用例图常见错误:把功能菜单当成用例
现象:用例图里出现「订单管理」「用户管理」「报表管理」这样的椭圆,整张图画成了菜单树,看不到用户目标。
原因:把功能模块当成了用例。「订单管理」只是模块名,它不是一个参与者的完整业务交互。
解决:回到参与者视角问「用户来这里要完成什么目标」,答案是《创建订单》《查询历史订单》《申请退款》,这些才是用例。清理时把「订单管理」拆成具体的下单、查询、退款用例,再按 include/extend 串联公共子流程,比如《创建订单》include《校验库存》。
5.2 类图常见错误:关系泛滥与可见性缺失
现象:一张类图里十几个类,几乎每两个之间都连一条线,箭头方向随意;属性没有可见性符号,方法没有参数类型,整个图停在分析阶段。
原因:画图的人没有区分关系强度,把一切交互都画成关联;也没有把设计信息补进图里,类图失去了设计价值。
解决:先删掉所有连线,再按依赖最弱、组合最强的顺序重新连线。方法参数里的类型是依赖,不画关联;只有长期持有的成员引用才画关联。整体和部分同生共死画组合,可以各自独立存在就画聚合。缺少可见性和类型的类图直接打回,补完再评审。
5.3 动态图常见错误:序列图画成数据流图、状态图当活动图
现象:序列图里出现数据库表名和 SQL 操作,生命线写着「orders_table」,消息是「执行 UPDATE 语句」;或者把订单状态迁移画成带分支的流程图。
原因:把系统当数据流理解,而不是面向对象。序列图的生命线是对象不是数据表,消息是方法调用不是数据库操作;状态图关注单个对象的状态集合和合法迁移,活动图才画分支。
解决:把数据表改成实体类,SQL 操作改成对 Repository 接口的方法调用。数据库操作属于实现细节,分析阶段不出现在序列图里,设计阶段也建议只画到 Repository 层。状态图画之前先列出这个对象的全部合法状态,再画事件驱动的迁移,出现「如果、否则」分支就说明该用活动图。
5.4 include 和 extend 用反:用例关系符号最隐蔽的丢分点
现象:《下单》对《库存校验》用了 extend,语义变成「下单时可选做库存校验」;《退款》对《审批》用了 include,语义变成「每次退款都强制审批」,和业务规则正好相反。
原因:把「异常处理」和「公共子流程」弄混。include 强调子用例是主流程的固定组成部分,extend 强调在特定条件下才插入扩展片段,它和主流程不是固定绑定。
解决:硬判断标准是「去掉这个子用例,主流程还能不能走通」。不能走通就是 include,能走通且只是某些条件下插入就是 extend。画完关系后把每个 include 和 extend 读成一句白话,再和产品经理核对一遍,这是性价比最高的检查方式。
5.5 工具与文档的坑:图元规范与.docx导出丢线
现象:用 Visio 画的类图复制进 .docx 后箭头变成直线、菱形变小、图片模糊;用 StarUML 导出的图元符号和教材不一致;软考手绘时被扣分。
原因:Visio 的 UML 模板部分图元不是严格标准,尤其是空心菱形和虚线箭头显示容易错位。StarUML 这类专业工具图元规范,但导出图片时分辨率设置不对,线条在缩放中丢失。手绘则是符号细节不到位。
解决:团队里统一用 UML 专业工具,我常用 PlantUML 和 StarUML,生态严格按标准画图元。导出进 Word 时选 SVG 或 EMF 矢量格式,只能发 PNG 就把 DPI 提到 200 以上,这样评审投影也不糊。软考手绘盯四个判分点:空心三角与实心三角不混、菱形实心空心严格区分、虚线实线不含糊、箭头务必指向目标端。细节到位,图就能拿分。
5.6 图与代码漂移:评审通过后没人维护图
现象:设计评审时的类图和三个月后的代码完全是两个系统,图成了挂在文档库里的僵尸图。新人照着图接手的代码,接口对不上,越查越乱。
原因:把画图当成一次性动作,迭代时只改代码不改图,图和代码之间的绑定关系断掉。
解决:把图放进代码仓库,用 PlantUML 这类文本化工具管理,和源码一起提交、一起 review。代码改动涉及接口、类关系、依赖方向时,必须同步更新对应的图,图才能成为可持续依赖的设计资产。这个流程我给每个项目都定成硬规矩,比任何建模规范都管用。
6. 验证你的UML设计:用可追踪性检查把图变成设计决策
设计图画完不等于设计完成,还要做一次追踪检查,把用例和设计模型绑定起来。做法是建一张表:用例、分析类、设计类、关键方法,每一行必须能回答「这个用例在哪些类里落地,调用哪些方法」。某个用例找不到任何方法,是漏设计,必须补;某个方法没有任何用例引用,是过度设计,要删。这张表也直接是软考案例分析题的答题框架。
| 用例 | 分析类 | 设计类 | 关键方法 |
|---|---|---|---|
| 下单 | 订单、库存 | OrderController、OrderService、StockService | submit、checkStock、save |
| 退款 | 退款单、支付 | RefundController、RefundService、PaymentGateway | createRefund、refund |
最后跑一遍设计评审检查清单:每个用例至少有一个设计类实现;每个类的方法都能追溯到一条用例步骤;依赖箭头不指向具体实现类;组合关系中整体负责部分的创建和销毁;包图里不存在循环依赖;每个接口的方法都被全部实现类使用。
这套检查我会在每次设计评审前自己先走一遍,不放过的原因是图和代码漂移的成本最高。长期养成的习惯是:每次迭代先改图再改代码,图永远跟着代码同步前进,而不是画完就归档。希望帮到你。
本文还有配套的精品资源,点击获取