ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

图书馆管理系统UML建模:从用例图到类图顺序图完整指南

图书馆管理系统UML建模:从用例图到类图顺序图完整指南 简介图书馆管理系统UML设计是一份面向信息管理与信息系统、软件工程等专业学生的课程设计参考资料完整呈现图书馆管理系统的分析与建模过程。文档从开发背景入手阐述系统目标、功能需求并围绕读者管理、书籍管理、借阅管理和系统管理四个核心模块展开帮助读者理解图书借阅业务从手工方式向信息化管理转变的关键需求。压缩包共包含一个PDF文档大小约803KB内容紧凑便于下载后直接学习目前已有一百三十四人浏览学习适合在系统分析与设计课程作业、毕业设计或UML实践训练中作为参照。文档重点给出用例模型与用例描述覆盖读者、图书管理员、系统管理员三类参与者的主要操作并针对借书、还书、续借、罚款等典型场景进行说明同时讨论了数据库安全性和完整性要求如视图权限、主外键约束、检查约束、触发器和级联更新等。读者可借此掌握图书馆管理系统的需求规格编写方法以及从业务流程绘制用例图、完善系统设计的整体思路。1. 图书馆管理系统需求分析与用例建模的开局方式拿到一份图书馆管理系统的课程设计很多人第一反应是打开 Visio 开始画矩形和箭头结果画完用例图才发现参与者分不清、用例边界模糊后续类图和顺序图全部返工。这份《图书馆管理系统UML设计》文档的价值恰恰在于它先做了一件事把需求分析拆成系统目标、功能需求、安全性完整性要求三个层次再从中识别出读者、图书管理员、系统管理员三类参与者最后才进入用例图、活动图、类图和顺序图的绘制。也就是说所有 UML 图形都是需求驱动的不是凭空画的。这篇文章会按照这份设计文档的推进顺序把每个建模阶段的选型理由、图形要素和可复现的画法讲清楚重点落在借书、还书、图书管理这几个核心用例上并给出可以直接套用的 PlantUML 代码和参数说明。无论是做 UML 课程作业、准备毕业设计还是要把这套设计转成实际代码都能从这里找到可执行的路径。2. 活动图建模借书与还书流程的分支验证2.1 活动图的核心元素与泳道划分用例图只回答了谁做什么但借书这件事从读者提交借阅证到最终借阅成功中间要经过图书管理员扫描条形码、系统验证读者资格、判断可借数量、创建借阅记录、更新图书状态和读者可借本书这串动作是有严格先后顺序的。活动图就是用来描述这种业务流程控制流的它的基本元素包括起始节点、活动节点、判断节点、分支与合并、泳道。起点和终点可以用实心圆和牛眼符号表示这在 PlantUML 里对应start和stop关键字。判断节点用菱形表示在 PlantUML 中就是if语句。泳道也叫分区用来区分不同参与者负责的活动图书管理员的动作、读者的动作、系统自动完成的动作分别放在不同的泳道里这样一眼就能看出职责边界。文档中的借书活动图正好体现了这一点查找图书、验证借书证、扫描图书条形码是图书管理员的操作验证是否可借是系统逻辑创建借书记录是数据持久化动作提示借书成功又回到用户界面。活动图在这个阶段的作用不只是画一张流程图它实际上是后续顺序图的业务基础。活动图关注的是发生了什么顺序图关注的是对象之间如何发消息两者不能互相替代。如果活动图中出现了验证是否可借这样的判断节点那么顺序图中就必然要有对应的查询读者信息、查询借阅记录、返回可借状态这三条消息。反过来如果顺序图画完了发现某个步骤在活动图中不存在说明业务描述有遗漏或者顺序图画多了。2.2 借书活动图的 PlantUML 落地直接用文档中的借书用例活动图作为蓝本在 PlantUML 中可以这样表达startuml |图书管理员| start :查找图书; :提示不可借| if (图书存在?) then (是) :验证借书证; if (借书证有效?) then (是) :扫描图书条形码; :验证是否可借| if (可借数量充足?) then (是) :创建借书记录; :存储借书记录; :更新图书状态; :更新读者可借本书; :提示借书成功; stop else (否) :提示借书失败; stop endif else (否) :提示借书证无效; stop endif else (否) :提示图书不存在; stop endif enduml这段代码要表达的逻辑是先确认图书在馆再验证借书证有效性然后扫描条形码最后检查读者可借数量。三重判断的顺序是有讲究的图书不存在是最高频的失败场景最先判断可以减少无效的数据库查询借书证有效性属于身份校验必须排在业务规则校验之前可借数量是最后一道约束因为查询它需要读读者的借阅记录开销最大。如果把这个顺序反过来每次借书都要先查完整借阅记录系统响应时间和数据库压力都会上来。另外注意更新图书状态和更新读者可借本书是两个独立活动它们之间没有依赖关系所以如果系统支持并发这两个更新可以并行执行但实际实现中通常会放在一个事务里避免出现图书已借出但读者可借数量没扣减的中间状态。2.3 还书与超期罚款的扩展还书活动图和借书活动图在结构上是对称的但多了两个关键分支判断是否超期、计算罚款金额。文档中给出的还书流程是扫描图书条形码、验证是否超出日期、创建还书记录、更新读者已还本书、更新图书状态、提示还书成功。其中验证是否超出日期这个判断节点直接决定了是否进入罚款分支。这里有一个在 UML 建模时容易被忽略的问题罚款金额的计算逻辑放在活动图里要不要展开我的建议是不要展开活动图只画到提示罚款、交纳罚款这个粒度就够了罚款金额的具体计算公式应该放在类图中的罚款记录类或者在顺序图中由罚款处理对象的消息来体现。原因很实际金额计算属于业务规则业务规则变更频率远高于流程本身把规则细节画进流程图以后改一次费率就要改一次图维护成本太高。活动图保持流程稳定把易变规则下沉到类和对象方法中这是保持模型长期可用的关键经验。3. 对象类建模与类图设计8 个核心类的属性与关系3.1 类的识别方法与属性分层这份设计文档列出 8 个类图书类型类、图书信息类、读者信息类、图书管理员类、借阅记录类、罚款标准类、罚款记录类、读者借阅状态类。类的识别不是拍脑袋而是从用例描述和活动图的宾语中提取名词。比如读者查询图书用例中出现图书的 ISBN/ISSN 号图书信息就会出现图书信息类借阅用例中出现借阅记录可借本书就会出现借阅记录类和读者借阅状态类。这里值得注意的一个点是图书类型类和图书信息类的划分。图书类型类只保存图书编号、图书所属标题、图书状态三个属性图书信息类保存索书号、书名、作者、出版社、单价、出版日期、分类、摘要、关键字、副本数、馆室号等。这两个类的边界其实是题录和馆藏副本的关系图书类型描述的是这本书是什么图书信息描述的是馆里有多少本、分别放在哪。再看读者信息类和读者借阅状态类。读者信息类的属性包括读者编号、姓名、性别、学号、类别编号、类型、学院、专业、年级、办证日期读者借阅状态类的属性是读者类别编号、类别名、允许借阅最大数、持有图书最长期限、借阅证期限。这两个类一个是读者档案一个是可复用的借阅规则配置。这种拆分值得借鉴如果允许借阅数量和借阅期限直接写死在读者信息表里每个读者的借书规则就要逐条维护改成独立的读者借阅状态类后同一类别的读者共享一份规则调整规则只需要改一条记录。3.2 8 个类的核心属性表类名关键属性建模作用图书类型类图书编号、图书所属标题、图书状态图书题录与在馆状态图书信息类索书号、书名、作者、出版社、单价、出版日期、副本数、馆室号单本馆藏信息读者信息类读者编号、姓名、学号、类别编号、学院、专业、办证日期读者档案图书管理员类管理员编号、姓名、密码、权限、所属馆室号操作员身份与权限借阅记录类读者编号、图书编号、借阅时间、应还时间、归还时间借还历史与在借状态罚款标准类罚款标准号、标准名、适用对象可配置的罚款规则罚款记录类图书编号、读者编号、罚款金额、处理状态罚款明细与催缴读者借阅状态类类别编号、允许借阅最大数、最长期限借阅规则配置3.3 类图与类间关系的判定类图画得对不对取决于关系类型判断是否准确。先看读者信息类和借阅记录类一个读者可以有多条借阅记录一条借阅记录只属于一个读者这是典型的一对多关联关系。在 PlantUML 中用1 -- 0..*表示。借助工具画类图时关系类型选错是最常见的失误下面给出借书场景下的核心关系实现示例startuml class ReaderInfo { - readerId : String - name : String - readerTypeId : String getReaderInfo() updateBorrowCount() } class ReaderStatus { - readerTypeId : String - maxBorrowNum : int - maxHoldDays : int } class BookInfo { - bookId : String - title : String - authors : String - status : String getBookInfo() updateStatus() } class BorrowRecord { - recordId : String - bookId : String - borrowTime : Date - dueTime : Date createRecord() returnBook() } ReaderInfo 1 -- 0..* BorrowRecord : 借阅 ReaderInfo 0..* -- 1 ReaderStatus : 类型归属 BookInfo 1 -- 0..* BorrowRecord : 被借阅 enduml这段类图代码要表达的关系有三层含义。读者信息和读者借阅状态之间的关联没有使用继承而是组合原因是读者类型变化的可能性存在把规则配置独立出来新读者类别只需要新增一条状态记录不需要修改类结构。借阅记录类和图书信息类之间是关联关系不是聚合或组合因为图书即使从未被借阅其基本信息和馆藏位置依然存在借阅记录只是借用过程中产生的临时关联数据图书信息并不依赖借阅记录而存在。这一点在判断关系时最容易出错很多人看到一条借阅记录对应一本书就画成组合关系导致图书信息失去了独立生命周期后续做图书删除功能时会出问题。3.4 属性类型与可见性设计属性前面的减号表示 private加号表示 public。UML 类图中属性要不要全部写类型取决于这张图给谁看。如果是提交课程设计或需求评审属性名和类型写到这个粒度就合适如果是要转成代码建议再加一层方法签名比如getBookInfo(title: String): BookInfo。设计文档里的类只描述了属性没有描述方法这是文档的一个不完整之处但也是一件好事它留出了自己补充的空间。补充方法时遵循一个原则方法名的动词应该能对应到某个用例的事件流比如借书用例里有创建借阅记录、更新图书状态、更新读者可借本书那就应该在 BorrowRecord 类中加createRecord()方法在 BookInfo 类中加updateStatus()方法在 ReaderInfo 类中加updateBorrowCount()方法。如果某个方法在用例和活动图中都找不到对应的操作基本上可以判断它是多余的。用用例作为方法来源可以避免在设计阶段过度设计。4. 顺序图推导从用例描述到对象消息时序4.1 边界类、控制类与实体类的划分顺序图描述的是对象之间在时间维度上的消息交互。画顺序图之前先要把对象分为三类边界类是用户界面相关的对象比如读者查询图书界面、图书借阅管理界面实体类是承载数据的对象比如读者信息、图书信息、借阅记录控制类是处理业务逻辑的对象比如借书处理模块。文档中的顺序图没有明确画出控制类而是让界面对象直接操作实体对象比如借书顺序图中输入读者账号、查询读者账号、查询读者借阅记录、借书处理这些操作都由图书借阅管理界面直接发起。在系统规模小、逻辑简单时这种画法问题不大但借书逻辑再复杂一些就不合适了。我的建议是引入一个BorrowController控制对象由它来协调读者信息查询、可借数量验证、借阅记录创建三个步骤界面只负责传参和展示结果。4.2 借书顺序图的 PlantUML 表示文档中借书用例的顺序是图书管理员输入读者账号、系统查询读者信息、查询借阅记录、返回信息、借书处理、查询图书编号、生成借阅记录、返回借书成功。把它画成 PlantUML 顺序图推荐用下面这种结构startuml actor Librarian participant BorrowUI as UI participant BorrowController as BC participant ReaderInfo as RI participant BookInfo as BI participant BorrowRecord as BR Librarian - UI : 输入读者账号 UI - BC : searchReader(readerId) BC - RI : getReaderInfo(readerId) RI -- BC : readerInfo BC - BR : getActiveBorrowRecords(readerId) BR -- BC : borrowRecords BC - BC : checkBorrowable() BC -- UI : 可借状态 Librarian - UI : 扫描图书条形码 UI - BC : borrowBook(readerId, bookId) BC - BI : getBookInfo(bookId) BI -- BC : bookInfo BC - BR : createRecord(readerId, bookId) BR -- BC : borrowRecord BC - BI : updateStatus(bookId, BORROWED) BC - RI : updateBorrowCount(readerId) BC -- UI : 借书成功 enduml这条消息链的关键在于借书成功后有两个更新动作更新图书状态和更新读者可借本书。在顺序图中这两个消息是先后发出的但在工程实现上建议放在同一个数据库事务里。如果只更新了图书状态读者可借数没扣下一次借书时校验就会漏掉这本书导致可借数量超过上限如果反过来先扣了数量但图书状态更新失败图书会被重复借出。顺序图在表达这种时序关系时是扁平的它不负责表达事务边界所以设计文档里要在顺序图旁边备注更新图书状态与更新读者可借本书需保持事务一致性这个备注比画图本身更重要。4.3 顺序图与用例描述的一致性校验顺序图画完后要做一次一致性检查用例的基本事件流中的每一条动作在顺序图中必须能找到一个对应消息顺序图中的每一条--返回消息在用例描述中要么有对应的后置条件要么是基本事件流中的某一步。比如读者查询图书用例的基本事件流是输入 ISBN 号、实例化 Book 类、加载图书信息、显示图书信息对应到顺序图就是查询图书、通过图书号查询、返回图书信息、显示图书信息这四条消息顺序和职责都对得上。如果发现顺序图中有条返回消息在用例描述里找不到对应通常说明这条消息是多余的反过来如果用例描述中有一步操作但顺序图里没有任何对象响应它说明顺序图漏画了消息。在校验还书顺序图时尤其要注意超期分支文档中的还书用例有弹出超期对话框、显示超期时间和应处罚金额的可选事件流顺序图中必须出现对应的判断节点和消息否则说明顺序图不完整。4.4 消息类型与实际调用方式的对应UML 顺序图中的实线箭头表示同步消息虚线箭头表示返回消息还有异步消息用开放箭头表示。在课程设计文档里大多数交互都是同步请求/响应模式画成实线和虚线即可不需要区分太多线型。但理解消息类型对后续编码有直接帮助同步消息意味着调用方要等待结果返回对应 Java/C# 中的普通方法调用异步消息意味着调用方不等待结果对应消息队列、事件总线或async方法。在借书这个场景中所有操作都是同步的必须拿到数据库返回结果才能继续下一步但提示借书成功之后的日志记录、通知读者等操作就可以设计为异步消息。如果在设计文档里把这两个不同性质的消息用同一种线型画出来实现时很容易忽略异步化的可能性错过性能优化的机会。5. 从 UML 模型到具体实现包图组织与类图转代码的映射经验5.1 按子系统划分包图UML 包图在课程设计中经常被忽略但它是连接设计模型与工程代码的重要桥梁。按照文档中的五个子系统划分包结构可以这样组织basic-business包对应基本业务功能子系统放借书、还书、预订相关的用例basic-data-entry包对应数据录入子系统放图书信息和读者信息录入相关的边界类与控制类query-service包对应信息查询子系统放各类查询用例database-manager包对应数据库管理功能子系统放实体类和持久化相关的类。包名对应子系统典型类basic-business基本业务功能BorrowController、ReturnControllerbasic-data-entry数据录入BookEntryUI、ReaderEntryUIquery-service信息查询BookQueryUI、ReaderQueryUIdatabase-manager数据库管理BookInfo、ReaderInfo、BorrowRecordsystem-security系统管理AuthController、UserManager包与包之间的依赖关系要限制在合理范围内查询服务包可以依赖基本业务包的数据接口但反过来不行。做到这一点后续团队分工、按包测试和代码复用都会顺利很多。UML 用例图到包图的映射其实是一一对应的用例图中的每个功能模块在包图中都能找到归属。如果画包图时发现某个类不知道该放哪个包多半是类职责划分得还不够清楚。5.2 类图转代码时对文档中属性的取舍类图转代码不是简单的一一对应需要结合具体技术栈做取舍。文档中读者信息类包含年龄、性别、地址、电话这些字段但如果用 Java 和 MyBatis 实现age字段建议由birthday计算得出不直接入库图书信息类中的图书摘要和图书关键字如果是大段文本在 MySQL 里需要选择text类型并留意全文索引的创建方式。借阅记录类中图书名、作者这两个字段在借阅记录表里属于冗余字段但实际系统往往选择冗余因为借书成功后如果图书信息被修改或删除借阅记录仍然要能显示当初借的书叫什么名字。这些内容在设计文档中不细讲工程落地时却会直接影响表结构设计。5.3 用例图中被忽略的边界条件与错误处理路径文档中异常事件流都写着没有权限给出错误提示这是一类非常典型的占位式描述工程实现时还需要自查以下几个风险点def borrow_book(reader_id: str, book_id: str) - dict: reader get_reader(reader_id) if not reader: return {code: 404, msg: 读者不存在} record_count get_active_borrow_count(reader_id) max_num get_reader_max_borrow(reader.reader_type_id) if record_count max_num: return {code: 4001, msg: 可借数量已达上限, current: record_count, limit: max_num} book get_book(book_id) if book.status ! AVAILABLE: return {code: 4002, msg: 图书当前不可借, status: book.status} with transaction(): update_book_status(book_id, BORROWED) update_reader_borrow_count(reader_id, record_count 1) create_borrow_record(reader_id, book_id) return {code: 200, msg: 借书成功}这段代码的code区分 4001 和 4002 是在边界条件设计时的一个细节。可借数量超限和图书状态不可借是两类完全不同的业务异常前端拿到 4001 时可以引导用户去续借或归还拿到 4002 时可以提示用户查询其他副本。如果把两类错误都返回同一个提示用户无法自助判断下一步操作。这和活动图中判断分支的设计一脉相承活动图里画了几个判断业务逻辑里就应该有几个对应的异常返回。另外注意事务边界一定要放在业务方法内而不是让 UI 层来控制提交和回滚否则后续接入 RPC 接口或消息队列时会遇到事务失效的问题。5.4 对三个类属性细节的再审视回到文档中的类定义我会重点检查三处。第一图书类型类的图书状态和图书信息类的图书副本数要配合使用如果某个 ISBN 有 5 个副本状态字段就不能只记录一个值而是要给每一条副本记录单独维护状态。在类图中这体现为图书类型类和图书信息类之间的一对多关联1 -- 0..*。很多人在画课程设计类图时忽略了这个数量关系直接在图书类型上画一个状态字段数据和图就不一致了。第二罚款标准类和罚款记录类的关联关系文档中没有明确给出但罚款记录类中应该有罚款标准号字段作为外键。第三读者借阅状态类和读者信息类的对应关系需要注意一个读者可能借了多种类型的书、按不同类型分别计算期限如果系统支持这种规则原来的类结构需要拆成多对多关联。设计文档以学校图书馆为背景规则简单但把这个边界识别出来答辩时能体现考虑问题的完整度。5.5 使用 Visio 绘制时的常见坑热门搜索词里的 Visio 画 UML 类图在课程设计阶段碰到的概率不低插一句实际操作经验。Visio 的 UML 静态结构模板中类之间的关联连线默认不显示重数需要右键连接线选择设置形状格式添加多重性标记。组件之间要通过连接工具拖动端点来建立关系不能直接画线否则导出为图片时连线偏移概率很大。更稳妥的做法是先用 PlantUML 把类图和用例图写出来验证逻辑再用 Visio 重绘提交到作业或论文里避免直接在 Visio 中边想边画改到后面形状一多连线错乱返工成本非常高。Visio 适合出最终图快速迭代验证适合用文本化建模工具分工明确效率会高很多。5.6 从用例到测试用例的推演UML 用例图还有一个在课程设计中体现不出来的实际价值就是它可以作为功能测试用例的编写依据。每个用例的基本事件流对应一条主测试路径每条可选事件流对应一条分支测试路径每条异常事件流对应一条异常测试路径。以读者查询图书为例基本事件流对应测试输入存在的 ISBN 返回图书信息可选事件流对应测试输入不存在的 ISBN 提示不存在异常事件流对应测试未登录用户查询提示无权限。借书用例则要额外覆盖可借数量临界值的测试比如可借数量正好等于上限时借书失败还掉一本书后可借数量减一再借时成功。测试用例完全可以从用例描述中直接翻译出来用例描述写得清楚测试设计就能省掉一半工作量。这个手法在课程设计文档里往往被忽略了但它恰恰是构建业务系统时最值得参考的建模经验。本文还有配套的精品资源点击获取
返回列表