301
社区成员
发帖
与我相关
我的任务
分享本次作业要求撰写的内容全部用📝️标出。
第四单元的任务是设计一个图书馆管理系统,主要目标是掌握对程序架构的设计和抽象能力,以及 UML 建模能力。
简单来说,图书馆每天白天开馆,夜晚闭馆(有时也会全天闭馆)。图书馆管理系统相应的任务是:在开馆期间接受各种用户请求,输出处理结果;在开馆和闭馆时整理图书,并输出图书的转运路径。
除此之外,第四单元与前三个单元的一处显著不同在于:我们需要先设计程序架构,然后使用 StarUML 绘制 UML 图,最后根据所设计的架构进行编程实现。
第四单元分为以下三次迭代:
第一次迭代需要实现借阅、还书、预约、取书、查询功能,以及开馆和闭馆时的整理功能。
除此之外,还需要提交 UML 类图。
第二次迭代需要实现续借和图书漂流功能,并增加了图书借阅期限限制。
除此之外,还需要提交 UML 类图和状态图。
第三次迭代需要实现用户信用分系统。
除此之外,还需要提交 UML 类图、状态图、顺序图。
以下是最终的类图:

可以看到,只用了数量很少的类就完成了复杂的功能:
Library 类:顶层接口,处理开馆、闭馆、请求等各种命令。Student 类:管理单个用户。Inventory 类:管理一系列书籍,是图书馆各个位置和用户“背包”的抽象。Book 类:管理一本书籍。BookState 类:书籍状态的枚举量。LibraryClock 类:管理图书馆的时钟,被其他类用于检查操作合法性。LibraryState 类:图书馆状态的枚举量。Main 类:主类,负责输入输出。以下是最终的状态图,描述书籍的状态:

以下是书籍的五种状态,恰好对应五个位置:
FREE:(正式)书籍位于书架,可自由使用。U_FREE:(非正式)书籍位于漂流角,可自由使用。ORDERED:书籍位于预约处,等待用户取书。BORROWED:书籍位于用户手中,正在被借阅。COOLDOWN:书籍位于借还处,等待被移回书架或漂流角。ORDERED 和 BORROWED 下方还注有一些属性名称,它们是仅在对应状态下可用的附加数据。
值得一提的是,因为这五种状态“恰好对应五个位置”,所以许多人认为它们是多余的——完全可以通过图书所处的位置来判断图书状态。
而我呢?我在第一次迭代时就为 Book 类设计了有限状态机,并绘制了简单的状态图。之所以这样做,并不是因为猜测或得知了第二次迭代要求画状态图,而是为了实现代码的自纠错——在图书状态出错时自动终止程序。后来我在网上查找资料时,得知这种设计方法被称为快速失败。

私以为状态图是这三类 UML 图中最有用的一类。有限状态机的思想在面向对象设计中也能发挥重要作用。
以下是最终的时序图,描述预约的过程:

可以看到,虽然我在状态图中已经略去了部分细节,但完整的流程依然很复杂——尤其是分支结构的嵌套。
在第四单元中,我们尝试了正向建模与开发,也就是先建立模型,再根据模型编写代码。
在本单元的每次迭代中,我都试着先设计,再编码,然后根据代码反过来修正设计,在反复修改中完成一次迭代。这种做法既能通过设计建立一个合理的、易用的架构,也能通过实现来补全架构中模糊不定的细节。相比之下,有些同学选择跳过设计直接编码——这样就很容易导致架构混乱,难以维护。
可惜的是,由于设计不足,编码过早,我在第三次迭代时还是出现了设计问题。在第三次迭代中,需要在已借阅书籍到期的当天对用户进行信用分的扣除。这就引出了两种选择:
方案一效率占优,且具有一定的扩展性(如果题目要求新增查询历史记录的功能的话,稍加修改即可实现)。而方案二代码量占优,无需对架构有大的修改。我没有充分考虑就选择了方案一,为此新增了 Record 和 RecordTable 两个类共计九十余行代码。后来我在重构期间,经过考虑认为这两个类没什么用,于是决定删掉这两个类,改用方案二。
除此之外,我的设计不足的问题还体现在下层接口上。在编码前,我虽然对需要新增的功能设计了顶层接口和数据结构,但并没有为其他类设计接口。这就导致我在编码时为了调用方便而乱开接口,这些接口功能混乱且用途单一,不少接口都只有 1 处引用。没办法,能花在 OO 上的时间还是太有限了。
最后我想谈一下建模阶段 UML 图的绘制。
虽然 UML 的功能十分丰富,但我们需要的只是其中的一小部分。这是因为我们使用 UML 仅仅是为了设计,而不是为了取代(所有或者部分)Java 代码。所以,UML 图不应画的太复杂,更不应 1:1 复刻代码,只要表达出代码的基本架构和运转逻辑,这就够了。
通过本单元的学习,我的建模能力有了很大的提升。现在我不仅可以在编码前进行设计,也可以用 UML 图准确规范地表达设计成果。这项技能可以加快编码速度、提升代码质量,对我们有很大帮助。
总的来说,《面向对象设计与构造》是一门富有挑战性的课程。它向我们展示了一种全新的思维模式——面向对象的思维,并通过四个单元的迭代开发,将这种思维付诸实践,提升了我们的面向对象的理解,加深了我们对面向对象的认识,锻炼了我们使用面向对象解决问题的能力。
这门课程锻炼了我的架构设计思维:从第一单元的层次化设计,到第二单元的多线程设计,我学会了使用面向对象思维设计复杂的架构。从第三单元的规格建模,到第四单元的 UML 建模,我学会了使用建模语言和建模工具对设计进行规范化。
这门课程也锻炼了我的测试思维:功能代码与测试代码总是相辅相成,共同进步。虽然测试的核心无外乎数据生成和评测这两部分,但构造高质量的数据总是难点。为此,我们需要反复阅读题目要求,确保数据生成器生成的数据既能满足题目要求(不超出数据范围),又能覆盖每一种情况。
面向对象课程终于结束了,一个学期的努力换来了一箩筐的知识,希望 OO 课能成为我们生命中一笔宝贵的财富。