☰
UML排课系统大作业建模顺序:从用例图到类图答辩不翻车
2026/10/14 11:20:30 网站建设 项目流程

简介:一份面向高校软件工程或计算机专业课程的UML大作业参考文档,围绕自动排课系统完整展示面向对象分析与设计过程。内容涵盖系统功能分析、活动图、用例图、概念层次类图、顺序图、状态图等,适用于学习UML建模、准备课程设计或毕业设计的读者。文档以课程作业形式组织,从教师意向、教室管理、自动排课、课表生成等场景入手,清晰描述各角色交互和类间关系,可作为排课类系统建模的范例。压缩包内共1个PDF文件,文件大小约780KB,便于阅读和打印。该资源已有1149人学习,内容完整,适合作为UML建模入门与进阶的参考资料。

1. 把UML排课系统大作业写成“能答辩的建模文档”,全靠这套建模顺序

软件工程课的UML排课系统大作业,交上去被导师当众问住的人,十有八九不是图太少,而是用例图、类图、时序图各画各的,三张图互相矛盾。这个标题看起来是一份“完整word版”的课程设计文档,但真正决定它值多少分的,是模型内部的一致性:用例里出现的角色,类图里有没有对应类;时序图里每个对象的消息,类图里能不能找到那个方法;状态图里写的状态词,和文档正文里的描述是否同一个词。这里要做的,就是把这个排课系统从需求、静态结构到动态行为完整理一遍,让读者能照着这套顺序复现一份能顺利过答辩的UML文档。它适合正在做软件工程课设的学生、准备软考中级UML建模题的考生,以及刚接手教务系统开发、想先梳理清楚业务边界的人。

2. 先定模型边界:排课系统的角色、业务流程与用例粒度

画UML最忌讳的就是打开工具直接画。排课系统看着简单,但“排课”和“选课”“调课”“教室借用”在多篇作业里边界常常被画成一个大杂烩,最后类图膨胀到二十多个类,答辩时连自己都讲不清。正确顺序是先把业务边界、角色和用例粒度定下来,后续所有图才有一个统一的锚点。

2.1 排课系统的领域边界:为什么“有课没人教”也能排出来

排课系统的核心矛盾,是教师、教室、班级、时间片这四个维度的资源冲突。一个排课请求进来,系统要同时回答四个问题:这个时间段有没有老师;这间教室这个时间段有没有课;这个班级这个时间段有没有其他安排;教室容量够不够装下这个班的人数。四个问题任何一个不满足,这堂课就排不进去。

建模边界也由此产生:只有那些被排课过程直接感知并受约束的实体,才需要进模型。比如“学生”可以出现,因为选课和容量约束要依赖人数;“学生宿舍”就不必出现,它不影响排课约束。这里有一个很实用的判断标准:如果某个实体从头到尾不会被任何一条排课规则引用,那它就不该出现在这张类图里,否则就是给评审留话柄。需求边界定下来后,再去看谁在操作这个系统。

2.2 六类角色与三个隐形需求:教秘、教师、学生之外的“隐形人”

排课系统的角色并不只是教务管理员、教师、学生三个。最容易漏的是教室管理员和系统管理员。教室管理员负责维护教室资源,比如某间教室的设备故障、暂时封楼、容量调整,这些信息变更会直接影响排课冲突检测的结果,所以必须作为一个独立角色出现在用例图上。系统管理员则负责账号权限和基础数据导入。还有一个看不见的角色:外部教务系统,它可能是数据导入方,也可能是成绩回传的接收方,在用例图上可以用参与者actor表示。

角色定了以后,每个角色对应的业务诉求也要同步列出来。教务管理员关注排课、调课、课表发布;教师关注查看课表和提交调课申请;学生关注查看课表、选课和查看考试安排;教室管理员关注教室维护和借用审批。把这些诉求落到用例图上,每个角色大概能对应三到五个有效用例。如果某个角色只有一个用例,比如“系统管理员——登录”,那就说明角色拆分过细,可以考虑合并。

2.3 用例图的粒度:选课、排课、调课三级用例怎么写才不空

用例粒度是UML大作业里最容易被批的一点。新手常犯的错是把系统的内部操作当成用例,比如“把排课结果存储到数据库”“计算教室冲突”“更新教师状态”,这些是实现层面的动作而不是业务目标,画到用例图上会显得整个系统非常“程序化”。评审想看到的用例一定是以角色为主语、以业务价值为结果的描述,比如“发布新学期课表”“提交调课申请”“查询空余教室”。

这里我一般按用户目标级来控制粒度:一个用例要能够回答“这个角色通过这个功能完成了什么目标”。比如教务管理员,“排课”是目标级用例,“设置课程的周课时”“指定上课教室”属于操作步骤,不应该单独成为用例。“调课”也类似,“提交调课申请”是一个用例。“审批调课申请”是另一个用例,两者的主角色不同,业务价值不同。如果你顺带在备考软考中级,这个粒度判断在案例分析题里同样适用,把动作分解到“用户能感知的目标”这一层就停,再往下就是系统内部设计了。

2.4 一份能直接抄的排课系统用例清单

用例清单是大作业文档里最好用的一页,它向评审展示了你的需求分析是完整的。这里给出一份排课系统常用的用例清单,覆盖了主要角色。你可以在文档里以表格形式直接使用,再按自己作业要求增删。

编号用例名主角色级别触发事件成功结果
UC01登录系统所有角色子功能级用户访问系统进入各自工作台
UC02维护教室资源教室管理员用户目标级教室信息变更教室资源表更新
UC03创建排课任务教务管理员用户目标级新学期开始生成待排课任务
UC04自动排课教务管理员用户目标级排课任务启动生成初版课表
UC05调整课表教务管理员用户目标级存在时间冲突课表修正
UC06发布课表教务管理员用户目标级课表确认无冲突师生可查看课表
UC07申请调课教师用户目标级教师时间冲突调课申请单生成
UC08审批调课申请教务管理员用户目标级收到调课申请申请通过或驳回
UC09查看课表教师/学生用户目标级用户打开课表页面展示当前学期课表
UC10选课学生用户目标级选课开放生成选课记录

用例图不建议一张图画到底。排课系统的用例图拆成“排课管理”“选课管理”“基础数据管理”三张图更清晰,一张图只放六到七个用例。下面这段PlantUML画的是“排课管理”用例图,包含排课、调课、课表发布三个核心流程:

@startuml left to right direction actor "教务管理员" as admin actor "教师" as teacher rectangle "排课管理" { usecase "创建排课任务" as UC03 usecase "自动排课" as UC04 usecase "调整课表" as UC05 usecase "发布课表" as UC06 usecase "申请调课" as UC07 usecase "审批调课申请" as UC08 } admin --> UC03 admin --> UC04 admin --> UC05 admin --> UC06 admin --> UC08 teacher --> UC07 UC04 ..> UC05 : <<include>> UC03 ..> UC04 : <<include>> @enduml

逻辑说明:这段代码把“创建排课任务”“自动排课”“调整课表”三个用例用include关系串起来,表示自动排课必须发生在创建任务之后;而调整课表包含在自动排课的主流程里,任何一次自动排课都可能因为冲突而进入调整分支。“发布课表”和“申请调课”不挂include,是因为它们有独立的触发条件和业务结果。参数说明:left to right direction让actor在左侧、用例区在右侧,适合导出到Word时保持横向空间紧凑;“< >”的虚线箭头方向要严格指向被包含的用例,方向画反会被当成依赖关系扣分。

3. 从用例到类图:排课系统的核心类设计与关联符号落地

用例图定的是“谁做了什么”,类图要回答“系统里有哪些东西、它们是什么关系”。这是UML大作业里评审最认真看的一张图,也是后续时序图和状态图的依据。类图画不好,后面所有动态图都会跟着翻车。

3.1 从用例文本中提炼类:名词法和职责法

我一般分两步做类图。第一步是名词法:回到前一章的用例清单,把每个用例描述里出现的人、物、单据圈出来。比如“教师提交调课申请”,这里有两个候选类:教师和调课申请单;“教务管理员审批调课申请”再次出现调课申请单,说明它确实是独立类。第二步是职责法:问一问每个候选类是不是承担了一个不可拆分的职责。比如“教师”承担的是维护个人基本信息、参与开课;“调课申请单”承担的是记录申请信息、推动审批流转。如果一个类同时承担两个互不相干的职责,就要拆开。

排课系统推荐类清单如下,字段不必一次写全,但核心标识字段要体现出来:

类名一句话职责关键属性关联对象
Course课程定义courseId, name, credit, hoursSemesterCourse
Teacher教师基本信息teacherId, name, titleSemesterCourse
Classroom教室资源roomId, building, capacityScheduleItem
StudentGroup班级定义groupId, majorName, studentCountSemesterCourse
SemesterCourse学期开课计划semesterCourseId, semesterCourse/Teacher/ScheduleItem
ScheduleItem排课单元(具体时间+教室)scheduleItemId, weekdays, periodSemesterCourse/Classroom
Enrollment选课记录enrollmentId, studentNo, scoreSemesterCourse

我一般会在类图里给每个类只填两到三个关键操作,比如createSemesterCourse()、checkConflict()、publishTimetable()。不要试图把每个setter和getter都写上去,那会让类图变成一张代码转写图,评审一眼就能看出你没有建模思维。

3.2 类图箭头符号:六大关系在排课系统里的具体画法

类图关系符号是答辩高频问题,也是软考中级UML建模部分常考的知识点。这里直接把六种关系整理成表,表格里的例子全部对应排课系统的真实场景:

关系类型符号排课系统例子生命周期特征
继承空心三角实线用户类派生出教师、学生子类复用父类属性
实现空心三角虚线排课策略接口被自动排课算法实现类实现接口约定
关联普通实线教师与开课计划之间的授课关系双方长期存在,互相知道
依赖虚线箭头排课服务依赖冲突检测算法仅在方法调用期间临时出现
聚合空心菱形学期开课计划包含多个排课单元总体与部分可分离存在
组合实心菱形调课申请单包含调课明细行部分随总体创建和销毁

最容易画反的是依赖和关联。判断方法是:如果A类的方法里创建了B类对象、传给另一个方法当参数、或者接收B类返回值,且A并不长期持有B,那就是依赖;如果A里直接声明了一个B类型的属性,长期保存引用,那就是关联。比如ScheduleService里的checkConflict()方法需要临时使用ConflictChecker对象,这里就是依赖,用虚线箭头从ScheduleService指向ConflictChecker,而不是实线。

3.3 核心类图的PlantUML代码与类职责说明

下面这段PlantUML可以直接生成排课系统核心类图。它覆盖了课程、教师、班级、教室、学期开课、排课单元和选课记录七个核心类,关系上刻意做了区分,避免全部使用千篇一律的实线关联。

@startuml class Course { - courseId : String - name : String - credit : int - hours : int + createSemesterCourse() } class Teacher { - teacherId : String - name : String - title : String + checkAvailability() } class Classroom { - roomId : String - building : String - capacity : int + isAvailable() } class StudentGroup { - groupId : String - majorName : String - studentCount : int } class SemesterCourse { - semesterCourseId : String - semester : String - isApproved : boolean + generateScheduleItem() } class ScheduleItem { - scheduleItemId : String - weekdays : int - period : int + checkConflict() } class Enrollment { - enrollmentId : String - studentNo : String - score : int + selectCourse() } Course "1" -- "0..*" SemesterCourse : 开设 Teacher "1" -- "0..*" SemesterCourse : 讲授 StudentGroup "1" -- "0..*" SemesterCourse : 面向 SemesterCourse "1" *-- "0..*" ScheduleItem : 生成排课单元 Classroom "1" -- "0..*" ScheduleItem : 承载 SemesterCourse "1" -- "0..*" Enrollment : 产生选课记录 @enduml

逻辑说明:这个设计里,学期开课计划SemesterCourse是中心类,它同时关联课程、教师、班级,代表“某个学期、某门课程、某位老师、面向某个班级”这个组合约束。ScheduleItem与SemesterCourse之间用了组合关系(实心菱形在SemesterCourse侧),因为排课单元离开了学期开课计划就没有意义——学期结束,开课计划删除,排课单元随之销毁。其他关系全部使用普通关联,比如Classroom与ScheduleItem是长期稳定的承载关系,教室不因某节课而存在,所以不画组合。参数说明:多重性标注1和0..*决定了数据库外键的方向,后续建表时可以直接参考:SemesterCourse表持course_id、teacher_id、group_id字段,ScheduleItem表持semester_course_id和classroom_id字段。

3.4 类图与数据库表的关系:不要画成两张皮

排课系统这类大作业,评审经常追问“类图能直接转成数据库表吗”。这里有一个原则:类图里每个类至少对应一张表,每个多对多关联要么拆明细表,要么用关联类。排课系统里Course和Teacher本来是多对多,同一个教师能教多门课、同一门课也能由不同教师教,我这里选择用SemesterCourse作为中间实体承接,这比直接在Course和Teacher之间画一条多对多更符合业务:因为开课计划本身还承载学期、班级、审批状态这些属性。

如果你最后还要写代码,类图里的每个操作也要能落到Service方法上。比如SemesterCourse里写了generateScheduleItem(),那后续时序图里就会看到ScheduleService调用它;如果时序图里调用了类图上没有的操作,答辩时就会被抓包。所以类图画完先别急着画下一张,回头把用例清单再过一遍,确认每个用例至少对应到一个类操作。

4. 让模型动起来:时序图、活动图、状态图怎么与用例一一对应

UML中的动态结构图包括时序图、活动图、状态图,这一整套在排课系统大作业里缺一不可。静态类图回答了“有什么”,动态图要回答“怎么协作”“状态怎么流转”“流程怎么并发”。动态图是答辩时长篇大论讲业务的好材料,但也是最容易和类图脱节的地方。

4.1 时序图:一次“排课冲突检测”的完整请求链路

时序图建议从用例UC04“自动排课”入手,这是全系统最有逻辑深度的场景。以教务管理员发起自动排课请求为例,参与对象包括教务管理员、排课界面、排课服务、冲突检测逻辑、教室仓储和课表结果。下面是PlantUML代码,展示了消息调用顺序和返回路径:

@startuml actor "教务管理员" as admin participant "排课界面" as ui participant "排课服务" as service participant "冲突检测器" as checker participant "教室仓储" as repo admin -> ui : 发起自动排课() ui -> service : 提交排课请求(semester) service -> repo : 查询可用教室(时间片) repo --> service : 返回候选教室列表 service -> checker : 检查时间/教师/教室冲突() alt 存在冲突 checker --> service : 返回冲突列表 service --> ui : 提示冲突,等待调整 else 无冲突 service -> service : 生成排课单元() service --> ui : 返回排课成功结果 end ui --> admin : 显示自动排课结果 @enduml

逻辑说明:这段时序图把“自动排课”用例拆成了七个消息,从界面层到服务层再到数据访问层三层清晰分开。消息编号不是必须写的,但PlantUML的书写顺序本身就代表了时间从上到下的流转,导出后要检查每个消息的返回箭头是否都用了虚线。这里有一个细节值得注意:service -> service : 生成排课单元()是自调用,对应的就是类图里SemesterCourse的generateScheduleItem()方法,评审追问时,你要解释这个自调用意味着方法进入了事务性操作,后续还要持久化到数据库。参数说明:alt组合片段用于表达分支,存在冲突和无冲突两个分支要覆盖所有可能的返回结果,不要只画成功路径,因为答辩时被问“排课冲突了怎么办”是最常见的问题。

4.2 状态图:调课申请单从草稿到归档的完整状态机

排课系统里适合画状态图的对象有两个:调课申请单和排课任务。以调课申请单为例,它的生命周期最能体现“事件驱动”的建模思想。先设计一张状态表,再照着画状态图,比边想边画稳定得多:

状态进入该状态的触发事件离开该状态的触发事件说明
草稿教师创建申请提交申请未提交前可修改
待审批提交申请审批通过/驳回教务管理员待办列表可见
已通过审批通过生效/撤销可被排课任务引用
已驳回审批驳回教师修改后重新提交需记录驳回理由
已生效课表发布无进入正式课表
已归档学期结束无只读状态

这里最常犯的错误是把判断条件画到状态节点里,比如在状态框里写“审批是否通过”。状态必须是名词短语,事件动词或动词短语,判断条件属于活动图或时序图的职责。调课申请单的状态图里,“已通过”和“已驳回”都是从“待审批”通过不同事件达成的,所以绘制时要保证“待审批”这个状态有两条离开路径;而“已归档”只有“已生效”在学期结束后触发,绝不能出现“已驳回”直接跳转到“已归档”,这在业务上是不成立的。

4.3 活动图与流程图:排课任务里的并发分支与泳道归属

活动图不是流程图。URL式的两张图看起来都是方框箭头,但活动图的表达重心是并行与同步,同时还可以用泳道区分职责归属。排课系统里最适合活动图的场景是“生成课表”这个流程,它包含三个可以并行的冲突检测分支:教室冲突检测、教师时间冲突检测、班级时间冲突检测。三个检测彼此独立,可以同时执行,这就是fork节点的意义;三个结果全部返回后在join节点汇合,再根据冲突数量决定“发布课表”还是“回排课调整”。

用泳道来组织活动图会特别加分:竖着划出“教务管理员”“排课系统”“数据存储”三个泳道,把“创建排课任务”放在教务管理员泳道,“执行冲突检测”放到系统泳道,“读取教室数据”放在数据存储泳道,评审一眼就能看出你理解职责边界。活动图的节点命名也要注意:统一用“动词+宾语”格式,比如“检测教室冲突”,不要写“判断是否冲突”这种模棱两可的表达,因为后者没说是谁在判断、判断什么。

4.4 把多张图拼进Word版PDF:导出前的排版与编号规范

这个标题里的“完整word版”和“PDF”不是随便写的,不少作业在工具里画得挺好,一放进Word就乱套。图的位置、编号、清晰度、页边距都属于印象分。我一般会在Word里统一做图注编号,格式是“图3-1 排课系统核心类图”,全部图按章节三级编号,方便评审按图索骥。图片插入方式不要截图粘贴,推荐在PlantUML或StarUML里直接导出为PNG或SVG后插入,导出分辨率设置在200dpi以上,确保转PDF后线条不糊。

排版上有两个要点:一是所有图统一宽度,不超过页面的左右边距,通常设置在14厘米左右;二是图注放在图下方,表注放在表上方,全套文档保持一致。转PDF时直接使用Word自带的“另存为PDF”,不要用在线转换工具,否则图表位置可能错乱。还有一个小技巧:所有类图里的类名、状态图里的状态名,在Word正文里出现时用相同的黑体字并加粗,检查时一眼就能看出全文术语是否一致。

5. 评审与答辩避坑:UML大作业最常见的五个扣分点

UML大作业看的不只是图好不好看,而是整套模型能不能自我解释。这里把这些年见过最多的扣分点按“现象→原因→解决”写清楚,照着一项项自查,能规避掉大部分答辩风险。

5.1 用例图和类图互相打架:用例里的角色在类图里凭空消失

现象:用例图里有“教室管理员”维护教室资源,类图里却找不到教室管理员对应的类或权限控制。评审问:“这个用例谁去执行?系统的哪个类响应它?”答不上来。原因:用例图和类图是分开画的,画完用例没有回头做角色与类的覆盖检查。解决:提交前做一次简单的矩阵检查——每个用例的主角色,必须能在类图中找到一个与之关联的类,或者是这个角色本身就是某个边界类的触发者。比如“维护教室资源”对应Classroom类和教室管理员的会话权限;“审批调课申请”对应调课申请单的状态变更操作。矩阵检查不需要单独写一页,用在Word里的一个表格就够:左边列用例,右边列关联类,对不上就补关系。

5.2 类图箭头方向画反:依赖和关联拿捏不住

现象:排课服务类与冲突检测类之间画了带空心菱形的聚合线,答辩被问“它们生命周期谁依赖谁”,当场没法解释。原因:把关联、依赖、聚合三种关系的视觉符号混成一种来用,只记得大概形状,没记语义。解决:画箭头前先问两个问题。第一个问题:A类是否在成员变量里长期持有B类?是则关联,否则继续问第二个问题:A类只是在某个方法里临时用到了B类?是则依赖。聚合和组合再追加第三个问题:B对象能否脱离A对象独立存在?能独立存在就是聚合,不能就是组合。排课服务和冲突检测器之间没有任何长期持有关系,冲突检测器只是一个被调用的算法,所以只能画虚线依赖箭头。

5.3 状态图画成了流程图:状态名写事件、事件当条件用

现象:状态框里写“等待点击提交按钮”,边上画了一个判断框“如果审批通过”,整张图变成了流程图的伪装版。原因:没理解状态是对象生命周期中的一个稳定阶段,事件是从一个阶段跳到另一个阶段的触发动作,判断条件是事件发生的规则。解决:认识状态图时,统一用“名词短语做状态名、动词短语做事件名”。排课任务状态图里,“待审批”是状态,进入它的触发事件是“提交申请”,“审批通过”是离开它的事件。如果状态图里某个节点不是在等待外部事件,而是在做判断,那这个节点不应该出现在状态图里,应该挪到活动图或时序图的alt分支里。

5.4 多套工具混着画,Word里图风格完全对不上

现象:一张类图是StarUML导出的,一张用例图是Visio手绘的,一张时序图又来自ProcessOn,三张图的字体、配色、线条风格完全不一样,答辩时被追问“这到底是不是同一套系统”。原因:每个工具都只熟悉一点点,哪个方便用哪个,忽略了全套图的风格一致性。解决:全篇统一使用同一个工具,MapUML或draw.io都能满足要求。导出前在工具里统一设置字体为宋体或微软雅黑,线条和边框统一黑色,着色只用一种强调色。如果工具导出的默认样式不合意,导出为SVG后统一在Word里用“图片格式→重新着色”调整。风格统一这件事虽然不影响功能正确性,但在答辩上是直观印象分,值得花十分钟处理。

5.5 文字描述与图形内容自相矛盾:文字说有软约束,图里根本没体现

现象:文档正文写“排课时应避开教师已提交的出差时间段”,但类图、活动图、时序图里都没有出差时间相关的字段或判断节点,评审一抓一个准。原因:大作业文档的文字部分是后补的,画图时没有把文字里的业务规则带进去。解决:导出PDF前做一次全文规则核对。把文档正文里所有带“必须”“不得”“优先”“避开”的句子抄到一张纸上,逐一去模型图里找对应实现。比如“避开出差时间”要在Teacher类里补一个unavailablePeriods属性,同时要在活动图的冲突检测分支里画出一条独立的“教师可用时间检测”路径。这一步很琐碎,但也是保住文档整体信用最有效的一步,模型图和文字描述一旦自相矛盾,整篇大作业的可信度都会被拉低。

6. 把大作业变成设计资产:用模型一致性反哺你的系统设计

UML大作业交了以后不要急着删文件,它其实是你在系统设计这条路上留下的第一份完整设计资产。我现在拿到任何一个新项目,第一动作就是把用例、类、状态三个核心模型快速对齐一遍,这个习惯就是从当年那份排课系统大作业里养成的。

具体的做法是答辩前给自己做一轮“三图交叉验证”。第一步,打开用例图,挑出三个核心用例,逐个追问“这个用例的发起对象是谁、系统哪个类负责响应、结果数据写进哪个类”。第二步,打开类图,确认每个关系符号两边都有真实存在的类,且关系方向与生命周期语义一致。第三步,打开状态图,把状态名和类图里的状态枚举字段逐一比对,确保同一个状态在全文只有一个叫法。完成这三步,如果你发现自己调课申请单的状态图里写了“已批准”,而类图字段里写的是“已通过”,说明术语不统一,赶紧统一成一个词。这一轮验证做完,你心里对这套系统逻辑会清楚非常多,答辩被追问时也能从模型之间的依赖链去回答,而不是靠死记文档。

做完这些以后,我还习惯把排课系统的类图当成数据库表结构草稿,把状态图当成工作流引擎的状态枚举,把活动图的并行分支当成任务调度里的异步节点。你会发现,这套UML虽然是为交作业画的,但它本质上是一份不需要写代码就能验证设计合理性的方案。特别是活动图里并发检测的那个fork/join结构,后来我用在真实教务系统里做排课任务队列时,几乎没有改动就落到了代码上。这也是为什么我一直不赞成把这份作业当作应付差事——你画图时对每个依赖、每个状态变化是否较真,决定了自己能从这门课里带走多少真东西。希望帮到你。

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

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

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

立即咨询