LCXKevin

面向对象设计与构造第四单元博客作业

一、作业的架构设计

|-Main
|-MyImplementation
|-MyUmlClassModelApi
|-MyUmlCollaborationApi
|-MyUmlStateChartApi
|-MyUmlStandardPreCheck

对 UML 类图、状态图和顺序图的分析各占一类,模型有效性检查为一类,四类的整体架构基本类似。

MyUmlClassModelApi类为例

public MyUmlClassModelApi(UmlElement... elements) {
       ArrayList<UmlElement> secondList = new ArrayList<>();
       ArrayList<UmlElement> thirdList = new ArrayList<>();
       readStepOne(secondList,elements);
       readStepTwo(thirdList,secondList);
       readStepThree(thirdList);
}
private void readStepOne(ArrayList<UmlElement> secondList, UmlElement... elements) {}
private void readStepTwo(ArrayList<UmlElement> thirdList,ArrayList<UmlElement> secondList) {}
private void readStepThree(ArrayList<UmlElement> thirdList) {}

没有新建各种诸如MyClass、MyInterface等类来保存信息,而是从读入的elements中提取有用的信息存入HashMap或HashSet中,从而在读入时就去除冗余信息,方便后续相关方法的使用。构造函数中分三次读入elements,解决乱序可能带来的空指针问题。当然不同的类中由于需求不同,elements在不同类中的顺序也会存在差异,但保证每类元素都在其可以读入的第一时间被读入。

具体到各方法时,由于读入的元素在一开始就已经确定,因此相同指令跑出来的结果也不会变,所以仿照上个单元将结果保存以便直接输出(虽然没什么大用)

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

第一单元是表达式展开。使用递归下降的方法,通过对表达式、项、因子、函数等对象进行层次化和模块化的建模与封装,将复杂的问题分解成多个步骤、多个层次,首先将高层次的表达式逐步分解为低层次的项和因子,再从低层次的项和因子开始化简,为高层次的化简提供更高的起点。如果说pre仅仅是让我们感受面向对象的思想,第一单元就能让我们体会到OO方法的强大。

第二单元是电梯问题。这一单元的重点不仅仅是对象的建模,生产者、消费者、共享对象、调度器,如何再生产等,更重要的是多线程下的对象间的并发交互。从第一单元的静态,到第二单元的动态,如何解决线程安全问题才是最让人头疼的,既不能无脑盲目上锁导致效率过低,也不能该加的地方不加导致出现线程安全问题,还要防止出现轮询,最终才能写出一台在规定时间内正确跑出结果的电梯。

第三单元是JML规格。这一单元的重点是基于JML规格的契约式编程,契约作用于需求方和供应方双方,双方都有一定的义务,否则契约失效,程序运行错误。简单来说,使用者需要保证前置条件满足;相应的方法需要保证后置条件满足;二者的交集构成不变式,不成立则程序错误。不得不承认契约式编程让这一单元的作业相对简单,但如何书写正确的JML规格着实不是一件简单的事,所以关键在于掌握这种思想。

第四单元是UML语言。这一单元的重点是对UML的解析,首先需要准确理解UML图的表示结构,元素类型、连接规则、表达方式;然后需要准确理解UML元模型的表示结构,理解元素的具体定义和相互间关系;最后需要根据UML规则检验模型的规范性。此前的作业让我们自己画UML类图和顺序图,一知半解的我确实画的不太好,学完本单元才有了更进一步的了解,也算是对面向对象的补充了。

三、四个单元中测试理解与实践的演进

第一单元是在久闻评测机之后第一次自己搭建评测机,加之学期一开始不太忙,还是投入了相当的精力。大体思路就是,数据生成、程序运行、正确性测试。数据构造是基于递归下降随机轰炸+学长博客提到的常量池,同时可以通过设置参数选择表达式中项的个数和括号嵌套层数。正确性则可以用sympy库直接判断。

第二单元的数据构造相对第一单元简单很多,但是随机数据的效果没有第一单元那么好,除了基本的功能实现可以使用随机数据,更应使用聚集性数据测试短时间内大量数据的高并发,关注超载、线程安全和tle的错误。正确性判断需要考虑总的时间是否超时、输出的时间戳是否递增、乘客是否到达目的地、电梯是否超载以及开关门和到达之间的顺序与时间差是否符合要求。

第三单元基于JML规格的单元测试可以很好的实现功能性测试,构造preOK和afterOK方法来对不变式进行检验。随机生成的数据需要控制异常与正常的比例,保证异常全覆盖即可,正常指令才是测试的重点。除此之外,需要针对时间复杂度高的方法构造复杂的图模型来卡T,经验表明时间复杂度为O(n^2)的方法基本都会tle。

第四单元受限于时间,仅仅是采用手动构造数据进行功能测试,最多是构造了一些可能产生空指针的数据,算是针对我自己的架构容易出现问题的地方进行测试。

四个单元的过程中,自动化测试从无到有,测试数据从单纯的随即轰炸到定位打击,根据需求手动构造极端数据,我觉得OO课程的学习使我对测试的理解有了长足的进步。

四、课程收获

  • 面向对象的一系列知识和实践经验,Java语法与设计模式、Java多线程、JML规格、UML图等

  • 迭代开发自动化评测,对测试的理解较之CO有了长足的进步

  • 在checkstyle规范下收获了合格的代码风格

  • 收获了能屈能伸的精神。进可耐心思考架构二次重构卷一卷性能分,退可百忙之中快速通过弱测中测静待强测炸裂(bushi

五、给课程的建议

  • 递归下降相关思想的训练放在pre中,缓冲第一单元第一次作业的难度。

  • 个人觉得用前面单元博客作业画UML类图来为第四单元做铺垫不如把第四单元放到第一单元为后面的博客作业画类图打基础。有个人因素在里面,但现在的模式下前面的类图我也没画明白,第四单元一开始也还是很茫然。这样也可以把相对轻松的第三单元放在临近烤漆完成。

  • 或许OO各项任务的开始时间可以自由一些,例如电梯单元前的假期时间很充裕却无法开始电梯单元,假期回来后的时间又略显紧张。周一晚上七点前不是那么忙,每周的作业却只能七点开始。

posted on 2022-06-27 16:53  LCXKevin  阅读(22)  评论(1编辑  收藏  举报