BUAA2024面向对象设计与构造OO第四单元总结

最后我们终于来到,一个句号~

第四单元的主要任务是完成小型的图书管理系统构建,核心是以UML建模语言指导完善自己的架构设计。本次博客的内容依旧按照给定要求完成,分为第四单元总结和整个课程总结两部分。


目录

一、正向建模与开发

二、架构设计

2.1 [hw13]

2.2 [hw14]

2.3 [hw15]

三、架构设计思维的演进

3.1 第一单元

3.2 第二单元

3.3 第三单元

3.4 第四单元

四、测试思维的演进

4.1 第一单元

4.2 第二单元

4.3 第三单元

4.4 第四单元

五、课程收获


一、正向建模与开发

本单元设计的主要目的是帮助大家能够实现先建模,拥有大致的核心框架和思路,在此基础上再进行代码编写。其实在前三单元的设计中或多或少已经有过类似的思考和尝试,例如在第二单元电梯调度中几类线程的构造,印象很深的是在后续加入RESET指令,双轿厢电梯时,自己也反复对之前的架构在草稿纸上增增减减,思考可能的架构和方案。

那既然建模成为本单元的主题,便需要有进一步的认识和尝试。个人感受来讲,在编写代码之前对自己的架构有深入的思考是非常有助于后续编写的。如果急于开始,边写边想,较大的规模下自己很容易就思路模糊混乱,产生bug的概率也随之增加。因为自己在编写时是具体到某个属性、某个方法的构造,太过局部,很容易就忘记了自己整体的架构是怎样的,越写越模糊。而如果拥有一个即使不那么详细的架构图,让自己的脑海中有一定的思路,是很有助于清晰地完成作业的。当然很多问题只有在编写过程中才会注意到,与此同时也需要不断改进自己的架构。总结来讲,先建模的作用就是让自己对几个关键问题有所思考,对自己将要编写的架构拥有清晰的认识,帮助自己进行具体的代码实现。


二、架构设计

2.1 [hw13]

第十三次作业自己的主要思路是建立给定的几个部门和Student类,其中Library类综合管理student和这几个部门,负责实现一系列功能。自己印象中比较困难的是各个部分图书的增删操作,他们和Library的增删有何关系?各个部门之间又有什么不同?这个过程很容易忽略了某些细节或者是忘记给某个容器删除元素导致错误,并且很难debug。这次编写中自己尝试增加更多的注释防止遗忘,回过头看确实有一定的效果,未来可以继续加强。

由于是本单元的第一次作业,因此自己的实现和最初思考的大致建模在架构上没有很大的差别,核心还是在各个类的具体实现上。真的只有在具体编写时才会体会到有何不同、有何需要具体注意的地方。本次作业类图如下:

其中自己为预约处建立了ReserveKey类,其内部存储了某本书的id和预约者的id,以区别出不同人借阅了同一本书。同时需要注意的是在用到判断该类的对象是否相等时需要重写hashCode和equals方法,也是和第一单元相呼应了。

public class ReserveKey {
    private LibraryBookId bookId;
    private String studentId;
//......
    @Override
    public boolean equals(Object o) {
    //...
    }
    @Override
    public int hashCode() {
        return Objects.hash(bookId,studentId);
    }
}

2.2 [hw14]

原本还在感叹道本单元第一次作业自己的构造似乎还算比较清晰,啊~也算是有进步了。结果在结束第二次作业后,自己的代码似乎又成了一言难尽的一坨......本次作业的主要内容是新增了图书漂流角和续借功能,图书类型的增加让代码中有了更多的判断语句,显得格外混乱。本次作业中出现错误最多的地方还是在开馆闭馆的整理流程,也是最复杂的地方。因为要实现图书向各个部门的移动,每次移动针对不同图书不同条件又有不同的方向,这时UML状态图似乎有一定的作用:

本次作业debug过程中印象十分深刻的一个错误是用hashMap<LibraryBookId,ArrayList<String>>存储了预约处所需要的书籍,当成功给预约处提供书籍后会把studentId从arraylist中删除,但自己却忘记了在arraylist为空时把对应的Key值删除。导致在后续续借书籍的判断条件中出了问题。然而自己没有意识到的是,在预约处中删除书籍自己又忘记了把预约处的books属性中的某个value(也就是该book对应的个数)减一,为最后一次作业永远难忘的debug留下了伏笔......

本次作业大致类图如下:

2.3 [hw15]

最后一次作业的主要任务是新增信用积分系统,印象很深的是本次作业的扣分处理。回想起来,最后一次作业自己似乎又是急于开始,并没有进行充分地思考,结果在编写过程中又是反复修改,很多细节自己在第一次读指导书时都没有注意到。最后考虑到本次作业的数据不会很强,还是采用了遍历所有学生的所有书籍,对借阅逾期和预约逾期的扣分进行处理:

//处理超过借阅时间的扣分
for (Student student : students.values()) {
   for (LocalDate deadline : student.getDeadlines().values()) {
      if (deadline.isAfter(lastCloseDay) && deadline.isBefore(date)) {
         /*sub score*/
      }
   }
}
//处理超过预约时间的扣分
HashMap<ReserveKey,Integer> overDues = ao.getOverDueBook();
for (ReserveKey key : overDues.keySet()) {
    /*sub score*/
}

本次作业架构上并没有太大的改变,最后的类图如下:

然而不得不提的是,当时自己在中测中第一个测试点出了bug,从下午到晚上,从晚上到早晨,自己反反复复找始终没有找到。最后不得不按照指导书一句一句地和自己的代码对应,最后发现居然是在hw14中提到的预约处书籍忘记减一的操作。因为自己在预约处针对不同需求用两个容器存储了预约处的书,忘记了对其中一个书籍进行操作。说来轻松,但当时找的实在艰难,实在是印象深刻且值得反思......

非常庆幸,本单元三次作业中强测均未出现bug。


三、架构设计思维的演进

3.1 第一单元

回过头看,第一单元似乎并没有非常重视自己的架构设计,最后自己写了足足十五个类。第一单元在架构方面主要是接口Factor的实现,诸如NumFactor、ExprFactor等。同时第一单元架构方面十分印象深刻的一点是把Expr、Term、Factor三个递归下降的层次归结为同一个类Poly,poly中又由最小单元Unit构造,进而进行统一处理。同时三个层次之间又有嵌套,联系还是比较紧密和易懂的。

3.2 第二单元

第二单元多线程的架构设计是自己印象最为深刻、也是自我感觉完成的最不错的一次设计。第二单元架构设计的核心在于多线程的交互,从InputThreadSchedule再到Elevator,三个核心线程之间拥有明显的输入->分配输入->处理输入并输出的逻辑。多个线程之间又通过Request等几个类联系在一起,在这一段单元中自己十分重视架构的提前设计和规划,最后看来还是有很好的效果的。

3.3 第三单元

第三单元由于是按照给定的JML完成作业,因此在架构上并不需要自己过多进行构造。然而为了实现并查集算法自己新建了DisjointSet类作为NetWork的一个属性,这样一种在具体的类中为了实现某种算法而构造抽象的属性,可能是第三单元中印象深刻的一点。

3.4 第四单元

第四单元没有任何博客的参考,让自己似乎又回到了oopre的冒险者设计。共同特点在于都是针对某几个具体的实际的部门进行类的构造,不同部门对应着不同的功能,所有部门又都由总的大类LibrarySystem进行控制。这样的设计是十分直接且符合认知的。

总的来讲,在面向对象设计与构造这门课中,架构的设计是十分重要的。自己在四个单元中体会到不同角度、不同侧重点的架构设计,也掌握了相比于其他语言更为抽象化、模块化的设计思维。


四、测试思维的演进

4.1 第一单元

第一单元自己的测试思路主要还是根据给定的表达式语法进行大量随机数据的生成,但现在看来,自己随机生成数据的强度并不高,同时自己也忽略了对于某些边界情况的手动构造。如果当时把两者结合起来可能会有更好的效果。

4.2 第二单元

相比于第一单元,第二单元的多线程由于难以复现的特点更需要大量的测试数据进行测试。因此需要足够高的测试密度和强度。第二单元测试比较关键的地方是涉及多个电梯的共同执行,因此不同电梯的输出不能存在矛盾,这也是第六次作业中自己强测出错的地方。同时还有电梯性能的考虑,最经典的还是“边缘时间输入大量数据”,这样一种边缘条件的测试非常能测试到自己的性能缺陷。

4.3 第三单元

和第二单元类似,第三单元的测试也重在对于程序性能的考察。因此测试数据的构造需要考虑到足够复杂的关系网络,针对某些复杂度高的方法进行大量测试,进而检测自己的复杂度是否合格,是第三单元的一大重点。

4.4 第四单元

第四单元测试的中心可能更需要放在某些指令过后各个部门的状态是否正确?有没有新增或者删除某些书?因此需要进行足够多类型的操作,让各个部门尽可能处于更多的状态,不同的状态下程序的执行是否正确。

总的来讲,个人体会到oo课中测试最为关键的部分在于足够高的覆盖率,大量且有效的数据能够帮助自己检测到更多的潜在bug。因此需要在构造样例时充分思考到足够多的情况,保证自己进行的诸多测试是有质量的测试。


五、课程收获

从听闻oo到实战oo,从oopre到oo正课,oo课程横跨了整个大二的学习历程,也必然是自己大学生活中印象最为深刻的课程之一。

学习过程中有很多难忘的瞬间,第一次尝试互测;第一次等待强测结果;第一次困难地debug;第一次在研讨课上分享自己的体会.......许许多多记忆尤深的瞬间,欣喜也好,失落也好,都是这个课程独特且浓墨重彩的一笔。

相比于oopre的十分艰难和痛苦,oo正课的学习其实比我想象中稍好一些,虽然仍旧痛苦。但我能够感受到自己有了更多的改进和提升,也和其他同学有了更多的交流和分享。

“能学到东西”,是我听过的对oo课最多的评价。自己在第三单元的总结中说“希望未来回头想想这学期的学习,自己能感叹道还是有很多收获和成长的吧”,至少对于oo这门课而言,确实如此。同时也很荣幸被抽中作为吴际老师理论课班级的一员,老师非常擅长在抽象的层次对一些概念进行分析和阐释,这是需要拥有足够深入的认识和清晰的表达能力才能做到的。同时oo课中撰写单元总结博客的方式让自己意识到这也是一种比较有效的反思总结方式,自己也比较喜欢瞎扯很多东西,未来可能也会运用到其他课程上。

最后,OO结束了,但学习的进程仍未结束。

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值