272
社区成员




正向建模与开发是一种自顶向下、从需求分析到系统实现的设计过程。它强调首先理解和构建现实世界的模型,然后将这个模型转化为清晰、健壮的软件结构。
但此次作业中涉及大量细节,所以搭建框架时不应过多关注实现细节,而是对所有要求有一个整体的布局与考虑。故而还是先整体完成的代码,再补充uml类图的细节。
AI以其独特的洞察极大地化简了此次作业的架构,但也使Library
略显冗长。
MainClass (驱动/控制器层):
职责: 作为程序的入口和总控制器,负责与oocourse框架交互,接收指令、管理时间的流逝,并将具体的业务请求分发给Library
类处理。
建模思想: 它模拟了现实世界中“时间”和“外部事件”对图书馆系统的影响。特别是对开馆指令之间日期的处理,通过循环逐天推进日期并调用library.checkReturn()
,精确地模拟了“每日自动检查”这一持续性后台任务,而非简单地跳跃时间。这种设计确保了业务逻辑(如逾期扣分)的准确性。
Library (核心业务/服务层):
职责: 扮演了图书馆这个“宏观世界”本身,是所有业务逻辑的核心。它管理着系统内的所有资源(书籍、学生),并负责执行所有具体的业务操作(借、还、预约、整理等)。
建模思想: Library类是整个系统的聚合根(Aggregate Root),它封装了BookCopy
和Student
等实体,并维护了系统状态的一致性。所有对内部实体的操作都通过Library
这个统一的入口进行,避免了外部直接混乱地修改内部状态,保证了模型的完整性。
Student 和 BookCopy (实体/模型层):
职责: 分别对现实世界中的“学生”和“书籍副本”这两个核心实体进行建模。它们封装了各自的属性(状态)和与自身相关的行为(规则)。
建模思想:
Student 不仅仅是一个数据容器,它还封装了学生自身的业务规则,例如canBorrow(), canOrder(), canRead()
等方法。这些方法将“一个学生能否执行某个操作”的判断逻辑内聚在Student
类内部,而不是让Library
类用一堆复杂的if-else来判断。这极大地提高了代码的可读性和维护性。
BookCopy 模拟了每一本实体书,它有自己的唯一ID、当前位置(状态)、历史轨迹等,清晰地反映了一本书从入库到流通再到整理的完整生命周期。
类图 (Class Diagram) 追踪关系:
类图定义了系统的静态结构,包括类、属性、方法以及它们之间的关系。
类与属性/方法: 代码中的Library, Student等类,及其内部的字段(如 students, creditScore)和方法(如 handleRequest
),都与UML类图中的类、属性和操作一一对应。
关系:
组合 (Composition): MainClass 创建并拥有唯一的 Library 实例,这在UML中表现为从 MainClass 到 Library 的实心菱形组合关系。同样,Library 初始化时创建并拥有所有的BookCopy,也是组合关系。
聚合 (Aggregation): Library 类中的 Map<String, Student> students 字段,体现了Library聚合Student的关系。在UML中,这表现为从Library到Student的空心菱形聚合关系,表示图书馆“包含”学生,但它们的生命周期不完全绑定。
关联 (Association): Student 持有借阅的书籍(heldBooks),这在UML中是Student和BookCopy之间的一个关联。
我们可以把大模型看作一个能力极强但需要指导的有力助手,而我们需要把握住整体,明确需求与实现要点。我们的主要任务是:
拆分任务:提出明确、高层次的业务目标和关键需求。例如,不要只说“设计一个图书馆系统”,而是说:“设计一个支持借还、预约、信用分、热门书籍和每日自动整理的图书馆系统。我们需优先考虑分层架构。”
明确指令:提供清晰的目标和约束,比如将整个指导书喂给AI并加上一些你对架构设计的一些思考。
持续追问:对它的方案针对性提问,让其总结它的优势与不足来引导它优化,以满足我们的最终要求。
简单总结就是:我们负责思考和决策,大模型负责快速生成方案和执行。
第一单元:面向对象的层次化设计
学习了通过递归下降构建表达式树,将解析、化简等功能模块化。尤其让人印象深刻的是需构建清晰的结构层次,明晰递归的流程是如何进行的,这对于管理调试代码有着重要的作用。
第二单元:面向模型的并发协同
面对多线程电梯,我的思维转向了如何构建一个健壮的并发模型。我采用了经典的生产者-消费者模式,将输入、调度、电梯分离为独立线程,通过共享队列协同。我第一次从单一流程思考转向系统协作,关注线程间的通信与同步。
第三单元:面向规格的性能优化
JML单元架构很大程度上由规格定义,核心挑战实际变成了如何选择最优的数据结构与算法(如HashMap、并查集、BFS)来满足性能要求。
第四单元:面向业务的抽象建模
UML单元旨在训练我们的“正向建模”能力,这是一种自顶向下的设计思维。架构设计不再是简单的功能划分,而是对真实业务流程的模拟与映射。
第一单元:手动构造
起步阶段,我的测试方法较为朴素,主要依赖手动构造用例。这种方法能发现明显bug,但覆盖率和针对性有限,效率不高。
第二单元:更强的手动构造
多线程带来了测试复杂度的剧增。但我始终抓住程序运行的核心逻辑,把握可能出现的各种特殊情况,进行尽可能全方面的覆盖。事实证明我捏的各种数据确实有效并有针对性,但毕竟人力构造有限,还得靠大佬室友的评测机。
第三单元:白盒测试与小评测机
JML单元引入了JUnit单元测试,但似乎测试的强度有限。我终于尝试写了一个小评测机,但在调试过程中发现了其很多小问题,最终改完后也并未构造出有太强针对性的边界数据(这还得手捏)。
第四单元:交互式测评
UML单元也只是捏了一个小评测机,有时测完也并不清楚是否就一定没问题了,还是得相信大佬室友的强力评测机(用过的都说好)。
抽象与建模能力的提升:课程逼迫我们跳出代码的细枝末节,从更高的维度去思考问题。无论是解析表达式、电梯系统还是图书馆,核心都是将现实世界或复杂逻辑抽象成清晰、合理的软件模型。这种能力是软件工程的基石。
对“工程”二字的敬畏:从JML的契约式设计到UML的正向建模,我体会到软件开发远不止“写代码”。严谨的规格、清晰的文档、可迭代的架构、完备的测试,共同构成了软件“工程”的可靠性。代码不仅要写得对,更要写得好——好到别人能看懂、能维护、能扩展。
拥抱工具,解放生产力:无论是IDEA强大的IDE功能,还是JUnit、JML、UML等工具链,亦或是本次作业中尝试使用的大模型,都让我认识到,优秀的工程师善于利用工具来保证质量、提高效率,从而将精力聚焦于创造性的设计工作上。
总而言之,OO课程为我打开了通往现代软件工程的大门。这段旅程充满挑战,时而“电梯惊魂”,时而“性能噩梦”,但最终我还是度过了OO的冒险。感谢助教和同学的陪伴与帮助,凡是过往,皆为序章。