2021_BUAAOO_第四单元总结暨课程总结

第四单元总结暨学期总结

一、第四单元架构设计

第一次作业

官方包中将UML类图中的每一个元素都抽象为了UmlElement,每个UmlElement中都存放了自身的id和其父元素(parent)的id,这样通过一个UmlElement查找它的父元素会很容易,但是想要查找子元素会比较困难,因此需要将官方包中提供的UmlElement进行组织,从而能够方便地通过父元素查找到它的子元素。我将官方包中的UmlElement进行了封装,实现了自己的MyElement,在MyElement中实现对子元素的查询。分析过需要实现的接口方法之后,我发现其中所需要的实现的类几乎都是围绕着类来进行的,某些UmlElement可以作为它的父元素的一个属性,而不需要专门封装这个类。举例说明一下就是,对于关联关系,虽然在UML图中,关联是作为类的一个属性的,但是我们实际上并不关心这个关联关系是什么,我们只关心这个关联关系对应的类是什么。因此在我封装的类元素MyClass中,将关联关系抽象为了一个ArrayList,其中装着这个类关联的其它MyClass。

经过 以上考虑之后,我设计出了上面类图所展示的各个类。我将MyElement作为所有元素的父类,其它元素根据自身独特的特征添加自己独特的属性,并提供访问相关属性的方法。我将所有的MyElement装在了MyUmlInteraction2的一个ArrayList中,将其中的类元素单独配备查询方法,然后在MyUmlInteraction2中实现需要实现的接口方法。

总体来说这次作业的架构设计比较简单,层次比较清晰。

第二次作业

第二次作业新增了处理顺序图和状态图的需求。考虑到对于顺序图和状态图的处理和类图几乎毫无关系,并且如果将对于三种图的处理都放在一个类中实现会显得比较臃肿,因此设计了三个管理类(ClassManager,InteractionManger,StateMachineManager)分别实现对于相关图的管理和查询。然后设置了一个MyUmlGeneralInteraction类,负责将三种图的元素分配到三个管理类中,然后调用三种管理类中实现的具体方法。

第三次作业

第三次作业新增的需求是对每种图进行检查,因此可以沿用第二次作业的架构,在每个管理类中实现对于每种图的检查。

这次作业的难点主要在于某些方法的实现,例如对于R002(检查循环继承),由于接口具有多继承的特性,因此对于接口的循环继承检查有一定难度。根据我的了解,可以采用tarjan算法或者动态规划算法来解决这个问题,但是这两个方法的实现细节我不是太明白,因此我还是选择了相对稳妥的dfs(深度优先算法)。考虑到R002在整个执行的过程中只会调用一次,因此dfs的复杂度是可以接受的。基于同样的考虑,对于R003和R004我也采取了dfs算法。

二、四个单元架构设计演进

第一单元

这一单元的任务是实现多项式求导。由于表达式是以字符串的形式给出的,对于计算机来说一串字符串本身没有什么意义,需要将字符串解析为计算机能够理解的形式,因此需要将一段表达式进行层次上的划分,这样就自然引出了层次化设计。具体实现是通过正则表达式将表达式划分为一个个独立的单元,并规划好各个单元之间的关系,从而实现了将一个表达式自上而下地分解。对于求导,在数学上是通过对一个表达式自上而下进行分解,分解到可以求导的程度之后进行求导,然后自下而上进行合并。于是我也采用相同的思路并使用递归的方法实现了求导(层次化设计使得递归十分容易实现)。

这一单元的作业让我明白了层次化设计对于提高代码质量和提高可拓展性的重要性。

第二单元

这一单元的任务是实现一个电梯。由于需要实现多线程,各个线程之间需要考虑到对于共享变量的互斥访问,这就是本单元的主题——线程安全设计。尽管主题是线程安全,但是层次化设计仍然是这一切的基础。我设计了一个主调度器线程负责接受任务和分派任务给每个电梯,每个电梯线程设置一个调度器负责电梯执行任务的顺序。相较于第一单元的作业,我的架构设计的层次明显清晰了很多。针对线程安全设计的要求,我并没有具体实现线程安全类,而是在每个线程里面添加同步块实现互斥。

在多线程的要求下,由于将一个个线程抽象为了对象,因而使得各个线程之间能够比较好实现同步。如果是面向过程,这种同步会比较难以实现,即使实现了也会比较复杂。

第三单元

这一单元的架构已经给出,不需要自己去设计。通过JML语言,一个类以及它的方法的实现被没有歧义地准确描述了出来。这种基于规格实现代码的方式提高了代码的实现效率,也提高了代码的质量。但是,每次作业的JML在发布之后都要经过多次改动——JML保证了实现代码的准确性,那通过什么方式来保证JML的准确性呢?

这一单元让我明白了规格的重要性。

第四单元

这一单元需要实现UML图的解析。作业的难点不在于架构,甚至可以说代码架构比第一单元简单很多,而是难在对于UML图的理解上。理解了UML图之后,作业也就迎刃而解了。

三、测试理解与实践的演进

第一单元我写了一个评测机,数据的生成是随机生成的。由于作业给出了表达式的生成式,根据生成式可以比较全面地生成测试数据,因而有着比较好的覆盖率。

第二单元是我测试做得最少的一个单元,基本只能靠自己手动写几个数据进行测试,这也导致了代码质量不高。

第三单元可以实现基于JML规格的测试,同时又获得了Junit这个强大的工具。通过JML限定的前置条件、副作用、后置条件可以对输入数据的种类进行一定的划分,每类数据只需要提供较少的样例就能取得比较好的覆盖效果,显著降低了测试的工作量和盲目性,提高了测试的目的性和覆盖率。

第四单元的测试主要基于和其它人对拍进行——主要是这一单元的边界情况比较多,容易发生理解上的偏差。在数据的构造方面,由于这一单元的指导书对于各种情况的划分比较明确,因此可以很容易地根据这种划分对每个方法的各种情况以较少的样例实现覆盖。

四、课程收获

  • 学会了java的基本语法
  • 学会了层次化设计
  • 学会了正则表达式
  • 学会了工厂模式
  • 学会了基于圈复杂度等概念分析代码质量
  • 初步掌握了多线程的概念以及线程之间同步的实现方法
  • 建立了线程安全的概念,并且在这种概念的指导下实现了电梯作业
  • 学会了基于规格实现代码和进行测试
  • 学会了使用Junit工具进行单元测试
  • 学会了读UML图,了解了UML中各个元素的关系和内涵
  • 学会了注重可扩展性以及减少耦合度
  • 复习了图论中的知识和算法

最后,学会了通过博客总结自己的学习状况。

五、建议

  • 感觉测试都是自学,没有比较系统的培养,希望设计几次作业专门学习怎么搭建一个比较好的评测机。
  • 把第一和第二单元降低难度或者往后排,因为一上来就这么大难度很难适应。
  • 每次作业结束后课程组提供一份“标准答案”,并且标识一下作业应当达到的要求(除了通过测试以外的要求,例如代码架构等),用于同学们学习。
posted @ 2021-06-23 23:20  康bao  阅读(54)  评论(0)    收藏  举报