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

一、总结本单元作业的架构设计

​ 这里展示一下第三次作业的类图,相当于整个单元的架构设计。

image-20220625154404819

​ 首先,通过第四单元手册的学习,我们可以得知UML类图、顺序图和状态图每一种图它的元素组成和元素之间的层次关系。那么既然我们想做的是一个UML的解析器,一种很自然的想法就是我们将重要的元素创建类,将UML本身元素之间的关系,转化成类与类之间的关系,并借此来实现元素的有序访问和有序统计。

​ 所以从整个类图就可以看出,主要实现类MyImplementationMyClassMyInterfaceMyInteractionMyStaMachine具有组合关系(Composition),而相应的,MyOperationMyClassMyInterface的组成部分,MyLifelineMyInteraction的组成成分,MyTransitionMyStaMachine的组成成分。

​ 从迭代的角度看,第一次作业主要实现类图的查询,第二次作业实现状态图和顺序图的查询。所以在MyImplementation的相应方法实现中,基本的流程就是根据输入找到相应的Class、Interface、Statemachine或Interaction对象,再调用这些对象里的方法,反馈结果或抛出异常。为了找寻到所求对象,我主要采用HashMap,实现按名字搜寻按id搜寻两大功能。

​ 第三次作业是对UML图的有效性检查。由于之前我们已经对图进行元素的层次建模,所以针对有效性检查,自然就是到具体的元素中去调用相关方法去检查其包含的对象是否满足需求。这里比较特殊的是我将R002、R003和R004三种规则新建了一个类来进行检查。原因有以下两点:

  • 这三种规则的检查不是能够在一个元素内部(比如Class或Interface或Statemachine)之中完全解决的,尤其是检查循环继承和重复继承,我单独建类可以更好地抽离Class或Interface之间的图论部分,这样就可以在类里把检查问题转换成单纯的图论算法问题,而且减少了原来在MyImplementation中可能对已有HashMap的干扰(不必要的访问和修改)。我认为这也算是开闭原则的体现吧。
  • 由于checkstyle的限制,MyImplementation里也放不下这三种检查的代码了。

​ 在实现算法上,第一、二次作业主要用到了记忆化搜索,第三次作业判循环继承用到了Tarjan找强连通分量,判重复继承用到了拓扑排序+记忆化。

二、总结自己在四个单元中架构设计思维及OO方法理解的演进

​ 首先简单回顾一下我们四个单元架构设计上的侧重点。

​ 第一单元是学会层次化设计,如何通过指导书的问题描述,划分出类和类里面的方法,同时运用Java面向对象的一些手段予以实现。

​ 第二单元关注于线程安全,我们需要了解哪里需要加锁,怎么加锁,以及电梯运行策略的探究。

​ 第三单元关注于JML契约式编程,正如我在第三单元博客中写的,如何学会“带着镣铐跳舞”,既要满足约束,又要追求性能。

​ 第四单元,从任务目的的角度式写一个UML解析器,但好像找不到一个合适的词来概括这一单元的训练方向。直到那天开总结大会,老师提到一个词“元模型”。那么这个“元模型”是什么呢?

​ 所谓元模型,就是模型的模型。参考了一下https://www.pianshen.com/article/15061956895/这篇博客的讲解,我发现其实这个概念在之前的学习经历中也出现了很多次。

  • 比如说线性代数里,最重要的就是那8条运算律,只要满足这8条运算律,就会发现许多东西都可以叫“向量”。你看,向量既可以有代数的形式,也可以有几何的形式(看起来更加直观),还有一些我们可能平时见不到的形式。我们想研究向量的某个问题,只需要取方便的那一面去做就行,而且大不了数形结合。
  • 比如说离散数学里我们研究过数理逻辑,5条公理就可以推导出一大堆当时令我们头痛不已的定理。当然,类似的还有集合和关系。

​ 这就是元模型的力量,也就是抽象的力量,给人一种万法归一的感觉。在软件的设计里面,我们会建立许多的模型,但是有些模型或许不用编码就能分析出其正误或者优劣,因为建模的过程可能就没有遵守好元模型的要求,好比某种意义上的“语法错误”。所以我们的第四单元就是通过写解析器的过程,更加深入地理解UML这些元素之间的关联和层次。那么当我们对UML掌握得不错时,其实再去放手使用UML工具设计具体的项目,或许就大大降低了犯一些基本错误的概率了。

​ 架构设计思维的进步,我想这和我们之前学写作文是类似的道理。首先先学会遣词造句,把句子造好,用上点修辞;然后,我们学把一个自然段写好。最后,我们学谋篇布局,让文章一气呵成。当然,我们不会说拿一篇高三的作文和初二的作文来比,好像前者比后者一个段里少用了几个比喻句就说高三的水平还不如初二,这显然是片面的。架构设计思维在这四个单元的演进,既不是线性递增的,也不是几个方面并列,而是循序渐进不知不觉中提高的。

​ 说到OO的方法,我会想到SOLID原则,会想到设计模式,会想到UML类图等等。Java和C++不同,它本身就是个纯面向对象的语言,那要完成这门课肯定是要使用OO的方法。但我想这门课既然叫《面向对象设计与构造》不叫《Java面向对象程序设计》,我认为我对OO的理解很大的进步,就在于信服许多问题的解决用OO是合适的并且知道怎么把需求进行分析和转化,能够对接相应的OO方法。比如说多线程,我们通过OS的学习知道其实一切的互斥并发的问题都可以通过PV操作来解决。但是假设我们的第二单元用C和汇编来写,纯面向过程甚至面向硬件,我想那体验会是相当痛苦的。但是,我们有了类、有了对象,我们的共享变量共享对象可以很明确表示出来。谁在竞争共享对象,怎么来管理这些竞争者,访问的次序、加锁解锁的流程,synchronize一下,配合好wait/notifyAll,这些问题就都迎刃而解了,再没有那么多烦心事和重复劳动。同样的道理,相比于了解工厂模式、单例模式的代码实现,我认为更重要的是通过实践知道什么需求、什么场合下,用设计模式,用OO的方法,是解决问题的最好办法。

三、总结自己在四个单元中测试理解与实践的演进

​ 测试是这门课作业中一个很重要的环节,其实也是未来进行软件开发的重要工作。第一单元中,我使用了sympy进行表达式化简的对拍检验,当然也吃过自动化不充分的亏。第二单元,则主要通过对拍+电梯行为评判器+可视化方法对程序进行测试。第三单元和第四单元主要采取覆盖性测试+专项检测的方法对软件进行测试。

​ 当然,除了自动化测试之外,我始终认为静态的代码检查是非常重要的,也就是说争取每次交作业之前,把所有的代码整个通读一遍。通读一遍的好处在于,一方面在编写的过程中,注意力其实都集中在某几个函数和变量上,虽然编码前肯定对整体架构有设计,但是如果不通读的话,其实也不知道整个项目做得如何,而通读一遍之后,也就很清楚知道整个代码的流程和最初的设计是不是一致,也会对编写测试程序有个基本的考量。另一方面,有时候这个bug往往出现在代码里很细微的地方,而无论是随机数据的黑盒测试,还是基于特定数据或JUnit的白盒测试,也不一定能揪出bug。所以通读也是对测试手段的一个补充。

​ 理想的情况下,我们能够对代码进行所谓形式化验证。因为有限的数据测试当然不一定能确保程序逻辑的100%正确。因此,在没有形式化验证的情况下,我觉得只有从提高测试用例的有效性角度入手。总结一些很常见的构造思路和手法:

  • 仔细阅读指导书,了解数据范围,将数据划分等价类,极限数据和常规数据分别测试
  • 常量池机制,以及控制随机数的分布(不如用取模概率的方法)
  • 通过时空复杂度分析构造能将优化和未优化代码产生分野的数据
  • 使用现实生活中的例子(尤其是第四单元的UML图,其实也可以拿之前博客作业画的图来试一试)

​ 事实上,同时作为程序的编写者和测试者,尤其是在编写白盒测试时,我们往往会有先入为主的观念,这是不利的。所以,无论是编写还是测试,首先都要审题,当然对于拿不准的地方可以与小伙伴们讨论咨询一下,不能闭门造车。

四、总结自己的课程收获

​ 我认为这门课程对我来说像是了解到“真正程序员是怎么写程序的”。小到checkstyle对代码规范的要求,工具链的使用,大到怎么阅读指导书、怎么设计架构、怎么测试程序,每周一次作业总是带着我“走了一遍流程”,这和我之前写算法程序或一些其他小程序是截然不同的。可以说,经过这一个学期的训练,我对编写千行级别带有工程性质的代码有了更多信心和把握,对于阅读工程项目代码也不再像以前那样完全摸不到头脑。
​ 从知识来说,设计模式、多线程、JML和单元测试等内容带我来到了一片新天地。一个是并发编程,另一个是软件理论。就像多线程中那各式各样的锁机制,就像研究JML能不能自动生成单元测试的探讨,当我们初步完成作业后,便意识到作业只是这些方面的一个入门,而这些方面还有更多值得深入探究的地方。
​ 当然,正所谓“独学则无友,孤陋则寡闻”。架构设计与代码测试中,我和小伙伴们也有许多思路的探讨,这些探讨非常宝贵,我从中也学到许多亮点,并多少转化为更好的设计和测试中去。
​ 荣老师的OO理论课真是非常精彩。每堂课荣老师总是能风趣幽默地讲述设计案例,并结合自己曾经在航天院所工作的经历来告诉我们一些“过来人的经验”,这让我受益匪浅,也对未来的职业工作有了新的认识。
​ 最后,非常感谢OO课程组的老师们和助教学长学姐们!没有你们的辛勤耕耘,很难想象这几个月来OO学习带给我观念上和能力上的改变与进步。

五、立足于自己的体会给课程提三个具体的改进建议

  1. 在作业的题目和需求设计上能够更好引导同学们学习使用设计模式。
  2. 第三单元JML规格的作业上强化对于具体业务的描述用途(就像实验中JVM垃圾回收机制,及作业中不同红包的收发行为),淡化对常见图论算法的“为JML而JML”的描述用途。
  3. 能够提供一些材料或者研讨课时间来讲解JVM的内存机制或底层实现。

posted @ 2022-06-25 15:54  LaiAng8086  阅读(86)  评论(3编辑  收藏  举报