2025_BUAA_OO_第四单元总结

王梓恒-23371355 2025-06-11 10:28:53

@

目录

  • OO第四单元总结
  • 第13次作业
  • 设计架构
  • 类设计
  • MainClass
  • Library
  • Bookshelf
  • BorrowReturnOffice
  • AppointmentOffice
  • User
  • Book
  • 第14次作业
  • 新增内容
  • 第15次作业
  • 新增内容
  • Unit4实践的正向建模与开发
  • Unit4架构设计
  • 大模型辅助正向建模体验
  • 四个单元架构设计思维演进
  • 第一单元
  • 第二单元
  • 第三单元
  • 第四单元
  • 总结
  • 四个单元测试思维的演进
  • 课程收获

OO第四单元总结

第13次作业

设计架构

类设计

MainClass

主类,只提供一个主方法,主要去调用其他类提供的方法,此处独立出一个Library类来统一接收响应图书馆的各种操作,主类通过Library提供的一个run()方法完成相应的图书借阅操作。

Library

图书馆,主要接收和响应各种操作,与输入输出指令进行交互。

所需属性:bookshelfborrowReturnOfficeappointmentOffice(三个基本部件,用于承担将指令操作分摊的任务)、HashMap<String, User> users(统计所有出现过的与图书馆进行交互的学生)、HashMap<LibraryBookId, Book> books(用来方便获取查询操作中每本书的去向路径)、date(当前时间)

所需主要方法:run(主要方法)、handle4Queried(处理查询操作,在本类完成)、handle4Borrowed(处理借书操作,下放到Bookshelf类完成)、handle4Ordered(处理预约书操作,下放到AppointmentOffice类完成)、handle4Returned(处理还书操作,下放到BorrowReturnOffice类完成)、handle4Picked(处理取书操作,下放到AppointmentOffice类完成)、arrange4Open(开馆整理操作,为了满足相应借还处无书、预约处有预期的书限制,在书架、借阅处和预约处三个地方完成)

Bookshelf

书架,处理与书架相关的操作,其实可以看作一个存储书本的容器,因此也可以作为借阅处和预约处存放书本的容器,例如从书架中将书取出,放入等,使用单例模式方便全局共享

所需属性:HashMap<LibraryBookIsbn, ArrayList<Book>> books(存储所有的书本,用isbn来标识一种书,便于借阅书籍查询是否还有该种书、从尾部删除)、bookshelf(单例)

所需方法:getInstance(返回单例)、addBook(将书本加入到books容器中)、popBookhandle4Borrowed(完成Library类下放的借书操作,若成功将书从容器中删除后返回;否则返回null)

BorrowReturnOffice

借还处,处理书籍的借还操作。

所需属性:ArrayList<Book> books(存储此处的还书)

所需方法:handle4Returned(处理还书操作)、arrange4Return(完成开馆整理中的将还书归还给使用单例模式的Bookshelf)

AppointmentOffice

预约处,处理书籍的预约操作。

所需属性:HashMap<String, Book> appointedBooks(存储每个学生的预约书本)、HashMap<LibraryBookIsbn, Queue<String>> registeredBooks(总共要被预约的书籍便于进行整理操作时的送往预约处)

所需方法:handle4Ordered(处理预约书籍的操作,根据用户条件判断是否预约成功)、arrange4Appoint(完成开馆整理中的将可放入预约处的书籍返回,利用单例模式的Bookshelf)、handle4Picked(处理取书操作,根据用户条件判断是否取书成功)。

User

用户,主要用来模拟书借出的情况和与图书馆系统交互的场景

所需属性:userIdHashMap<LibraryBookId, Book> ownedBooksisOrdered

所需方法:addBookpopBookcanBorrowBookcanOrderBookaddAppointmentcancelAppointment

Book

书,主要记录与书有关的信息,比如:目前持有者、当前所在位置和书的id等。

所需属性:idappointTimeexpireTimeArrayList<LibraryTrace> path(记录书籍的去向路径)

所需方法:getIdgetBookTypesetAppointTimesetExpireTimeisExpired

第14次作业

新增内容

相较于第13次作业,新增阅读和归还两种图书管理系统需要处理的请求。

新增热门书架和阅览室两个多出来的可以存放书的地方,其中前者和第13次作业的普通书架统称为书架注意:"书籍在架"指的是对应的ISBN号的任一副本在书架上

其中借阅、还书、预约、取书流程均未发生改变。查询流程中,可移动状态多了热门书架和阅览室

由于多了与阅览室相关的阅读和归还两个请求,因此需要新增一个阅览室(ReadingRoom)类完成相应的下层操作,例如:此处需要一个容器来存放被阅读的书籍(因为这里并不在意谁是否在阅读对应的书,用户的作用只是将书从书架拿到阅览室,因此不需要去记谁拿了哪本书,只是记得需要在该人拿了书之后得给其标记为拿过书的状态),同样也要提供增加阅读书籍handle4Read()handle4Restored()两种操作。

此外对于热门书架,我并不打算多增加一个类,因为其本质上需要做的还是与普通书架交换书以及与用户交互,因此将其作为一个属性放置在原有的Bookshelf中或许更方便书籍的交换,以及与用户的交互。

第15次作业

新增内容

引入用户信用分系统,新增图书借阅期限限制。
还书时新增需要确认是否逾期。
查询时新增查询某用户当前信用分。
新增图书借阅期限限制:

A类书无借阅期限,B类图书30天、C类图书60天
若某书借阅期限为x天,则从用户拿到借阅书(借阅成功和取书成功都算)的次日起算第一天,到第x天当日还书不算逾期,但是第x+1天还算逾期。
用户信用分限制:
初始信用分为100,上限180,下限0,
加分:
1.还书期限内还书(借书或取书成功后还书)立即+10分
2.阅读后当日主动归还(输入该用户归还指令)立即+10分
减分:
1.逾期还书:在该书还书期限的最后一日结束后,若用户仍未还书,用户信用积分立即-5,从逾期次日起到还书当天,每过一天信用积分-5
2.阅读后不还:当日闭馆后立即-10分。
3.预约后不取书:未在规定时间内取走书则当日闭馆后立即-15分。
不同信用分对应不同的阅读/借阅/预约权限:
/> 0:允许阅读B/C类书籍
/>= 40:允许阅读A类书籍
/>= 60:允许借阅B/C类书籍
/>= 100:允许预约B/C类书籍

User类新增score属性来代表该用户的信用分,同时就需要getScore()addScore(int score)来获取和修改信用分,对应了查询操作和实时变化信用分。新增modifyScore(LocalDate lastDate, LocalDate nowDate)方法来处理在开馆时对从上一次开馆到此次开馆期间由于借阅的书超过期限的信用分扣减情况。

Book类需要新增deadline属性来代表该书在某用户手中的借阅期限的最后一天,并增加int isDue(LocalDate date)方法返回传入日期同deadline之间的差,小于等于0自然还未过期限,否则超过期限。此外,还需要一个setDeadline(LocalDate date)来设置期限。

Library类新增lastDate属性来保存上一次开馆的时间,用于计算用户可能的信用分变化。

Unit4实践的正向建模与开发

本单元的第一次作业,我就是采用先正向建模再编写代码的方式,也就是先画好UML图然后再去编写对应的代码。在实践的过程中,确实发现一些不便,例如:在画图时确实会去思考到底要如何实现,而好不容易画好图后,又发现在真正的实践过程中总是会多出一些此前画图时并没有考虑到的地方,导致又需要去改图(为了通过评测),因此,这样的相互掣肘导致我经常要花很多的时间来画图和改图。
但是第一次作业之后的第二三次作业,继续迭代的时候,才感受到了正向建模的好处,一是在图上进行对应的修改后,可以对照着图来编写代码,不易出现纰漏;二是便于debug的时候对照着看。当然这些只是正向建模的一些好处,因为在真正大的工程项目中,往往建模比编码更重要,因为只有好的框架才能使实现能发挥出相应的作用,使编码不至于十分凌乱。(u1s1,对着图编写代码确实放心很多,像多了一份保证一样)。

Unit4架构设计

本单元是维护一个图书管理系统,围绕图书的借阅、预约等操作进行周转,因此我设计一个Library类来接收输入并向其余各部门发出操作请求,具体的相应操作大部分都是由具体对应的部门完成,此外针对书架、借还处、预约处和阅览室等图书馆具体部门各设计了一个类,为了交互方便,还设计了书和用户类。
如此一来,通过自顶向下的方式解耦操作,将比较复杂的工作下发给具体部门(类)来处理,就能很好的方便上层调用,而自底向上中底层只需要考虑此层具体操作的执行即可,只要每个底层部门都能执行好自身的功能,上层再进行合理的调用,就可以实现较为完善的代码功能,同时这样大大提高了debug效率,因为通过打断点或者printf大法定位错误后只需要去相应的类处理即可,并不需要在上层调用中去修改,因此也大大提高了可拓展性,使未来的迭代工作更加轻松
由于我是先进行UML图的建模,再进行最终代码的编写的(至少第一次作业是的),由于有图评测的存在,所以UML图基本上也是比较认真的完成的, 最终代码与UML模型基本吻合,我通过第一次作业的正向建模很好的使后两次作业的迭代只需要较为轻松的添加工作。此外,在第二三次作业的实现过程中,我也使用了课程组提供的@Trigger@Message来辅助状态图和顺序图的绘制,实现了两者之间的定位追踪关系。

大模型辅助正向建模体验

由于我在本单元使用大模型的次数不是很多,唯一的几次还是在实验课上强制要求的,因此我只能按我在实验课上的体验来讲,总体来说,大模型可以给出一个初具雏形的代码框架,但是其中的细枝末节还是需要人工的参与,但是在一些细节方面大模型确实做的还是不如人类。
在实验课上学到了ROLE等方法(实则只记得这一个了),所谓ROLE也就是让大模型带入一个角色去完成相应的任务,比如:假如你是面向对象编程大师,请你根据如下场景完成什么任务等等。此外,还有一种给定对应样例,例如:什么输入对应相应的可能的输出来使大模型学习其中的逻辑。
总之,我认为充分学会引导大模型来完成复杂场景的架构设计对于我未来的学习和工作至关重要,随着大模型的逐步发展,码农的岗位已经岌岌可危了,但是我们也不用悲观,新形势下,如何运用好大模型并辨析其回答都将是未来人才所不可缺少的能力。

四个单元架构设计思维演进

第一单元

通过使用递归下降的方法逐步解析表达式,将解析、合并、化简和优化解耦开来,逐步构建表达式解析的架构。虽然第二三次作业的强测作业并不理想,甚至第二次都没进互测QAQ,但是还是学会了很多诸如深浅拷贝区别与使用和递归下降思想等许多很有用的知识。

第二单元

使用synchronized机制构建安全的多线程程序,此外通过使用生产者-消费者模式、单例模式和工厂模式等使代码可读性更好,同时更具拓展性。此外,我还采用了自顶向下和从底层反推上层的设计思路,使架构设计上更加具有层次感。多线程下设计安全可靠的程序的挑战也让我不断加深了对于多线程架构设计的理解——使那些不同线程对于共享的临界资源的操作变为原子操作,不可打断,对于非共享的资源便可并行处理进而提高运行效率,或许这就是多线程的魅力吧!!!

第三单元

规格化设计即契约式编程下,大部分内容不需要自行去设计,也就是架构设计早已定好,但是为了实现这一架构却有着截然不同的实现,这也就是JML的规格和实现分离的理念所在,而在给定架构以外,我就本着性能优先的前提进行相应的设计(因为性能不够会没昏的),例如:增量式编程,期间使用了大模型对于一些算法进行润色。

第四单元

UML正向建模的背景下,需要自行设计架构并根据相应的架构完成程序设计,采用自顶向下和自底向上即可很好的完成相应架构设计。

总结

总而言之,四个单元的学习让我从面向对象小白成为了可以设计出有一定体量的可以跑起来的小程序员,还是很令我高兴的,要知道学期初的我还只知道一股脑的将方法集中在一个类中实现,经过四个单元的学习,我逐渐意识到了"高内聚、低耦合"的重要性,以及这个理念对于代码可读性和可拓展性的重要意义。此外,好的架构确实大有脾益,要不是有课程组提供的实验和训练,真的很难短时间内建立起一个足够优秀的架构,讨论区中的好思路也时常令我眼前一亮,这些都是架构设计的优势所在。

四个单元测试思维的演进

此前我对于“测试”的认知只停留在“通过数据点评测”即可,事实上,这并不能说明什么:在进行有实际意义的开发时,有时并不能有如此全面的测试数据,因为在功能上线之前,只有一些小测试;对于真正的“强测”——系统上线公测后的足够强、覆盖面够广的测试数据,若此时才找到bug就为时已晚了。
OO课程中,也有类似的机制,在中测时,有面向评测机修改代码的机会,但此时测试数据强度有限,通过这部分测试也并不意味着代码并无问题,真正的挑战是强测和互测,在这里一失足成千古恨。
上学期的OOpre课程使我对于单元测试有了一定的认识。这让我从以前只能干瞪眼和printf大法等的debug方法,进化到确保每一小部分的正确性,进而确保整个程序的正确性,这样的方法在测试层面更加底层,也更容易定位。虽然如此,我好像只在OOpre上用了,至少Unit1Unit2Unit4是这样。
本学期的Unit1,我并没有想起OOpre中的JUnit,我是采用编写评测机同同伴安全对拍的方式进行正确性检验,不过由于样例的不可枚举性,即使完全随机也无法实现覆盖式测试,导致我在在这一方面也吃了不少苦头,因此,还需要去手搓一些边界样例并结合一些中测数据,同时正确清晰的逻辑编写以及扩展性强、简洁的框架更是减少bug存在的前提。
本学期的Unit2,由于多线程程序结果的不可预知性,因此打断点的方式就不是很适应了,首先就是百试不爽的printf大法,在涉及到状态变化等可能出现问题的题目输出相应的状态和过程量。其次就是运动一会后再通读一遍代码,重新审视可能会有很不一样的感觉。最后就是多搓样例,尽可能在多种样例中复现问题,总结共性存在的问题。当然,更重要的是还是理解好代码,对症下药。
本学期的Unit3,由于此单元的每次作业都要求了Junit测试的需求,因此此单元主要采用的是JUnit的测试方式。由于此单元每次作业都要求对一个方法写Junit测试并且还需要通过一些测试点才能拿到中测分(总是因为覆盖面不全而爆红的我暗暗难受),而为了测试能够有较好的方法覆盖率,面向JML规格进行的功能测试就显得至关重要,主要是去考虑方法调用前是否满足了requires,调用后是否满足了ensures,以及是否只对assignablemodifiable修饰的变量进行了修改,副作用的考量是极其容易忽略的,在我第一次作业时就没有去考虑,虽然过了测试,但是在第二次作业的测试编写时有一个点——万恶的mid3,始终过不了,在浏览了交流群内信息后,我才幡然醒悟,因为当时的方法是pure的,也就是所有变量什么都不能修改,因此在方法调用后其实是要去判断是否有变量的属性因此被修改的,而这也正是我疏忽了要面向JML的严格测试导致的,因此全面的规格测试不只是requiresensures,尤其要注意副作用的影响。不过,u1s1,在完全利用规格信息来设计相应的Junit测试样例确实能够很好的测试潜在的问题(也能够更快通过相关的测试了),**效果很不错!!!**而这或许就是契约式编程的好处。不过由于,此单元不仅只有正确性的考量,对于用时过久的样例也会直接判错,但这是JUnit测试所不能及的,因此还需要尤其注意跑JUnit测试和本地跑样例的时间,学会了使用IntelliJ Profiler来观察的方式查看相应的CPU时间,进而定位耗时的地方。
本学期的Unit4,测试主要是交互的,比较有趣,但是由于期末临近,因此只是采用干瞪眼和借助其他同学评测机评测的方式来进行测试,虽然难以放心,但是效果确实还不错,没有自己搭评测机,也是十分可惜QAQ!
总的来说,OO使我对于测试有了更加深刻的认识,对我今后的学习工作十分有帮助。

课程收获

最重要的收获就是实现了从面向过程编程到面向对象编程思想的转变,同时还充分学习了Java语言。
另外OO课程还给了我与许多优秀同学交流的机会,在他们身上我学到了很多,一些我所不及的地方。
具体对于课程的感受大致如下:
总体感受还不错。在评测、数据点设置和互测方面体验较差,命题、上机实验、助教答疑、基本框架和研讨课等方面体验还不错。
对于体验较好的,比如命题:基本上都能很好的贴合单元要求,除了电梯的一些不太符合实际的设定外,感觉都还行;上机实验:强度适中,可以很好的辅助作业的完成,提供基本框架;助教答疑:帮助很大,能够帮助我们更好的理解指导书,进而正确的完成作业;研讨课:通过集思广益,很好的将大家的点子汇聚在一起,常常可以产生意想不到的火花
体验较差的:评测:评测机偶有出错,且第4单元貌似图评测不算分,感觉这样对辛苦画图的人有稍微有点的不公平。数据点:感觉有几次作业的强测数据点并不很符合强测的强度,覆盖的不是很广。互测:本身对这个机制并不反感,甚至觉得很有意思,但是私以为没必要给两天的时间来互测,感觉一天足以,因为一天时间没测出来的,多一天也于事无补,且多的那一天的互测刚好和下一次作业重合,假若出现bug,那互测挤压的时间加上bug修复的时间,会使下一次作业的迭代比较吃力,反而不利于迭代
总体体验还是很好,就是学分为什么这么低廉OO之旅就到这了,但是计算机的旅程还未结束,再会了,OO!!!

...全文
20 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

272

社区成员

发帖
与我相关
我的任务
社区描述
2025年北航面向对象设计与构造
学习 高校
社区管理员
  • Alkaid_Zhong
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧