301
社区成员
发帖
与我相关
我的任务
分享
在本单元的实践中,我通过绘制 UML 图逐步理解并改进系统设计。
类图:
初期设计中,Library 类承担了过多职责,造成高耦合,难以扩展和维护。
随着作业的推进,将功能逐步拆分到其他类中,如 Operation 类负责处理命令,Appointment 类记录预约信息,Person 类存储用户信息。
最终的类图较初期设计更为合理,各类职责更加清晰,系统结构更加易于理解和维护。
状态图:
状态图主要用于表示 Library 类的状态转移,包括 queried、borrowed、ordered、returned 和 picked 等状态。
尽管 Library 类过于庞大,但状态转移仍然清晰,帮助理清了图书馆操作的流程。
在反思过程中,认识到状态图在设计初期的重要性,它能够有效地指导系统的状态管理。
顺序图:
由于初期设计架构不佳,顺序图中很多操作都集中在 Library 类内部,显得过于简单。
后续作业中逐步将操作分布到其他类中,如 orderNewBook 和 getOrderedBook 操作不再全部由 Library 类负责,顺序图变得更为复杂和合理。
顺序图的绘制过程暴露了设计中的问题,促使对架构进行改进和优化。
状态图绘制完之后还觉得自己的架构尚可,但顺序图难以下手、羞于提交的时候,才发觉自己的设计远远不够。很遗憾直至homework15,才理解到UML图的意义;更遗憾直至oo要结束了,自己的架构还是很差、类的关联性不强。
只能浅谈一下自己关于UML一致性的一点薄弱理解吧。
一致性的重要性:
UML 图的一致性确保了系统设计的准确性,各图表应反映同一系统的不同方面,避免设计与实现脱节。
一致的图表有助于理解架构,特别是在开发过程中或工作被打断时,通过 UML 图能够迅速理清系统结构和行为。
架构理解与改进:
初期架构设计简单但高耦合,通过绘制和反思 UML 图,逐步识别出系统中的设计缺陷,并进行改进。
学会了逐步优化设计,将操作合理分布到各类中,提高系统的可维护性和扩展性。
正向建模的实践经验:
在构建和优化架构的过程中,通过正向建模逐步提高了设计的合理性。
UML 图不仅是设计的工具,也是反思和改进的有力手段,通过不断绘制和调整,逐步形成了较为合理的系统架构。
本次作业主要为构建图书馆基本模型。
架构设计:
除官方包中的类以外,我只设计了五个类:
Main类:处理输入,构建图书馆、完成图书馆中图书的初始化,逐条读入输入,交由Operation类中的handleCommand方法处理。
Operation类:接收Main类传递的输入指令,根据指令类型,通知Library类中的对应方法,并接收Library类对应方法的返回值(accept or reject),进行对应输出。同时,用HashMap<String, Person> persons记录来往图书馆的每一个人。
Library类:设置
HashMap<LibraryBookId, Integer> bookshelf 书架
HashMap<LibraryBookId, Integer> borrowReturn 借还处
ArrayList<Appointment> appointment 预约处
ArrayList<Appointment> wait 等待整理即将送往预约处的书籍队列
完成queried、borrowed、ordered、returned、picked相应转移操作,并向Operation类返回对应操作是否成功。
Appointment类:记录预约信息,包含书籍信息、用户信息、放置日期、放置倒计时。
Person类:存储用户id,用户所持有的B类、C类书籍。

策略:
整理策略:
闭馆整理:借还处到书架
开馆整理:预约处到书架,书架到预约处
好处:先将借还处和预约处的书籍收回书架,使等待整理即将放入预约处的预约尽可能得到图书。
预约处理策略:
先将accept的预约存入等待队列,整理时,如果书架上仍有对应书籍,则将该预约由等待队列转移至预约处;否则继续处于等待队列,等待下次整理。
好处:保证所有accept的预约能被放到预约处,避免当天整理时由于书籍不足预约信息直接删除。
后续迭代反思:
将所有操作的处理都放在了Library类中完成,耦合度高,架构不清晰。
用HashMap或者ArrayList形式指代书架、预约处、借还处,后续迭代过程中,预约处、借还处所存储的信息暴增,仅用hw13设置的HashMap或者ArrayList存储不便。
书籍信息只使用了LibraryBookId,没有额外建立Book类,导致后续出现DriftBook,很难办。
本次作业新增了漂流处,相应的,要完成图书捐赠、漂流处图书的借阅、漂流图书转正等任务。
架构设计:
Main类、Operation类、Appointment类基本同上次作业。
新增Book类,并细分为NormalBook类和DriftBook类,书籍类中记录书籍信息、借阅起始时间(为Person类服务)、借阅倒计时(为预约处服务)、借阅次数(DriftBook特有),同时实现判断书籍借阅/预约是否过期的方法。
Library类:
将借还处一分为二,分为borrowReturn和borrowReturnU
新增 HashMap<LibraryBookId, DriftBook> driftCorner 图书漂流处
增加renewed、donated操作
Person类:新增存放用户持有的BU类、CU类书籍,新增判断某本书籍是否过期的方法。

策略:同上次作业
后续迭代反思:
预约信息存储了用户信息,但用户中没有存储预约信息,导致hw15检查用户的对应的预约是否过期时遍历较为复杂,不得不做修改。
本次作业新增了用户信用分,是否按期还书、是否逾期取书、捐赠书籍将影响信用分,,并且从书架或图书漂流角借书、预约图书、续借图书等操作要根据信用分进行限制。
架构设计:
没有再新增类,只对类中的方法进行了修改与增加。
Operation类:在闭馆、开馆后,对所有用户的所有书籍进行搜查,判断是否借阅逾期并进行相应扣分。
NormalBook类和DriftBook类:新增对借阅逾期的判断。
Library类:
新添对“从书架或图书漂流角借书、预约图书、续借图书”操作的信用分限制
预约成功后,让用户保存该条预约信息;用户取书后或预约未取逾期后,对应用户删除该条预约信息。(保证用户对自己的预约信息的知情)
逾期取书、捐赠图书,改变信用分。
Person类:新增存储用户的预约信息,新增信用分对象和信用分计算方法,新增对持有的书籍借阅逾期搜查。

(Appointment与person互相知情)
策略:
借阅逾期处理策略:
闭关后、开馆前,检查所有用户所持有的每本书籍是否逾期,逾期则扣除信用分。
整理策略:
改为全部在开馆后整理:借还处到书架、预约处到书架,书架到预约处。
类图和代码设计的一致性:
初期设计:类图中的类和方法基本在代码中有所体现,但随着实现的细化, Library 类职责过重的问题逐渐暴露。
最终设计:在类图中新增 Book 类及其子类、调整后 Library 类、新增信用分管理和预约信息管理,代码实现与类图保持一致,但部分细节仍需优化。
状态图和代码设计的一致性:
状态管理:状态图帮助理清了 Library 类的状态转移流程,代码实现基本符合状态图描述。
状态清晰度:代码中的状态转移操作与状态图保持一致。
顺序图和代码设计的一致性:
操作流程:根据代码逻辑和流程画出简单的顺序图。
改进顺序图:顺序图中的状态难以转移,使得高耦合问题暴露无遗,也让我意识到架构的缺陷,因此调整了架构。随着架构改进,顺序图中操作分布更加合理,代码实现与顺序图逐步一致。
通过本单元的作业实践,从初期设计到最终改进,架构逐步优化,类职责分配更加合理。UML图在设计、反思和改进过程中起到了重要作用,帮助理清了系统结构和操作流程。最终代码设计与UML模型设计基本保持一致。
模块化与分层设计:将表达式解析与计算逻辑分离,通过解析类和计算类的分层设计,确保各模块职责单一,代码结构清晰。
数据结构设计:设计了Expr、Term、Factor等数据类,采用递归下降解析方法,有效处理表达式的各类操作和优先级。
并发控制与线程安全:在多线程环境中,通过同步块、wait()和notifyAll()等机制,确保线程安全,防止数据竞争和死锁;重视并发控制和线程安全,合理使用同步机制保护共享资源。
层次化设计:将输入处理、请求调度和电梯运行分别封装在不同的类中,形成了层次分明的架构,提升了代码的可读性和维护性。
规格与实现分离:遵循JML规范,实现代码与规格分离,确保代码的正确性和可靠性。
数据结构与算法优化:选择适当的数据结构和算法,优化程序性能:选择HashMap替代数组,提升查询效率;引入并查集优化连通性判断问题……
面向对象设计与分类:合理设计了Library、Operation、Appointment等类,体现了良好的面向对象设计原则。
分类与职责划分:本单元差劲的架构设计使我更加深刻地认识到,只有通过清晰的职责划分和类设计,确保系统的可扩展性和灵活性,才为后续迭代和功能扩展提供了坚实的基础。
测试依赖:过于依赖同学的测评机,自主性不强。
数据构造不足:未充分考虑构造最简洁、最易错、最麻烦、最大值的数据,导致测试覆盖面不足。
搭建测评机进行线程安全测试:针对并发问题难以复现的特点,编写简易测评机,通过多次运行同一组输入,监测超时情况,确保多线程环境下程序的稳定性。
手动构造数据:构造多种复杂场景,如单独一条reset、大量请求、不同时间点的reset操作等,手动检查程序在不同情况下的表现。
JUnit测试:编写JUnit测试用例,自动化测试,提高测试效率和覆盖率。
多种数据生成策略:仿照实验的测试数据,随机生成指令,覆盖各种方法调用,并手动构造特殊图(完全图、孤立点图)。
影子图技术验证pure:创建影子图,避免浅克隆问题,通过比较操作前后的对象状态,确保方法实现正确。
多种测试方法:反复调用复杂度高的方法进行性能测试;黑盒测试、白盒测试;全面覆盖:确保所有构造方法和类型都被测试;边界数据和极端数据:测试id的边界值和除法的除数为0等情况。
数据构造器:编写数据构造器,自动生成测试数据,提高测试效率。
代码阅读与交流:由于前两次作业难以自动化验证结果,更多依赖于阅读代码、与同学交流、找bug,特别关注书籍到期前后的测试,确保日期处理的正确性
边界测试:第三次作业有credit指标,由于上限设置和实现差异,和整理策略相似的同学对credit指标进行对拍。
从依赖到自主:从最初依赖同学的测评机,逐渐意识到自主测试的重要性,学会独立构造各种测试数据。
自动化与多样化:引入JUnit自动化测试,提高测试效率和覆盖率;搭建测评机进行多线程测试,确保并发环境下的稳定性。
性能与边界测试:关注算法复杂度,进行性能测试;构造边界和极端数据,确保程序在各种极端情况下的正确性。
数据构造较强、结果正确性验证较弱:注重数据生成策略,通过随机生成、手动构造、影子图技术等方法,全面覆盖各种可能情况,确保测试的完整性和准确性;但对于结果正确性的检验做的不好,对于自由性强、难以对拍的作业,很难想到检验思路,测难以进行评机的搭建。
十六周下来,oo不仅提升了我的编程技巧,还培养了我在复杂问题面前的耐心和解决能力。无论是架构设计、并发控制、测试编写,还是应对需求变化,都让我收获颇丰(尤其是和os比起来……)。
简单总结为以下几个点:
架构设计:开始懂得如何从宏观角度审视问题,构建清晰、模块化的软件架构。
多线程和并发控制:面对并发编程的挑战,,我经历了从对锁机制的困惑到逐渐掌握优化策略的过程,虽然一开始迷迷糊糊,理解并不深入,对于并发错误手足无措,但通过不断尝试和优化,逐渐理解了锁机制。
优化策略:电梯调度的优化让我从追求局部最优解的局限中解放出来,转而着眼于全局。我学会了如何在不同的场景下平衡资源利用和性能提升,能够针对具体问题挑选最适合的算法和数据结构,显著提高了程序的运行效率。
软件开发的工具:接触JML,我对代码规格有了全新的认知。UML图的学习让我能够将抽象的设计思想转化为可视化的图形,清晰地描绘出类之间的关系和交互。
测试:代码测试是软件开发中不可或缺的一环。通过实施黑盒测试、白盒测试以及JUnit测试,我学会了从不同维度审视代码的完整性和功能性;通过构造边界数据、极限数据、压力测试,我明白了代码安全性的重要意义,这也鞭策我写代码时多思多想考虑多种情况;通过编写测评机,我的代码能力也得到了提升。
平和的心态和坚持不懈的意志!
这学期在oo四个单元的切分下,过得格外的快。一学期以来,我总想着写到这个地方,我会输出很多的,但行文至此,却又不知道说什么了。
也曾为那一点点性能优化而锱铢必较,也曾因一点笔误谬以千里而深夜emo,但总的来说,和oo相伴的一学期很快乐!
感谢幽默风趣的荣老师,感谢每一位辛勤付出的助教,感谢dpo测评,感谢一路相伴的舍友,感谢小丑群里的大家,感谢老朋友smr,祝OO越来越好!