面向对象设计与构造第四单元及课程总结

OO课程告一段落,是时候总结总结了。

一.  第四单元作业的设计架构

  1.1  第一次作业

      这一次作业总体上花了我不少时间,为的就是能写出来一个像样的架构(毕竟前几个单元的作业简直无法直视)。

      这次作业主要的请求都是基于class和interface。因此我建了两个辅助类ClassInfoInterfaceInfo用来将具体实现分散到这两个类当中,而MyUmlInteraction这个主类负责就是调用辅助类中的相应方法。另外考虑到Attribute和Operation也比较复杂,因此我又建了两个辅助类AttrInfo和OperationInfo。

      举个例子,当我输入指令

CLASS_OPERATION_COUNT classname

      首先调用MyUmlInteraction中的对应方法

 1  public int getClassOperationCount(
 2             String s, OperationQueryType operationQueryType)
 3             throws ClassNotFoundException, ClassDuplicatedException {
 4         if (!className.containsKey(s)) {
 5             throw new ClassNotFoundException(s);
 6         }
 7         if (className.get(s).equals(" ")) {
 8             throw new ClassDuplicatedException(s);
 9         }
10         String classId = className.get(s);
11         ClassInfo classInfo = classHashMap.get(classId);
12         return classInfo.getOperationCount(operationQueryType);
13     }

      前9行是执行相应检查。接着找到对应的ClassInfo对象,调用相应方法

1  public int getOperationCount(OperationQueryType queryType) {
2         switch (queryType) {
3             case ALL: {}
4             case RETURN: {}
5             case NON_RETURN: {}
6             case PARAM:{}
7             default: {}
8             } 
9       }  

      这样就完成了一个指令的查询,其他指令的执行方式类似。这样以来对于debug就很友好,可以迅速找出错误在哪,而且改起来也很方便。

      很巧的是在中测截至前3个小时发现了一个bug,就是我没考虑接口继承多个接口,这样在进行一个类实现接口查询的时候就会有缺漏,在我定位到这个bug后,很快就改正过来了,只需要改InterfaceInfo中的一个方法(求一个接口继承的所有接口)。

      本次作业的UML结构图如下

                             

      可以看到,大部分的具体实现都在ClassInfo和InteractionInfo当中

      本次作业的方法复杂度如下

                                                     

       方法复杂度较高的两个类中发现两个方法复杂度较高

      

      

      经过分析,发现这两个方法的共同点在于都有多个if或者case语句,导致分支数目很多。

  1.2  第二次作业

      第二次作业基本上沿用了第一次作业的思想,将具体实现分散到不同的类当中

      为此我建立了StateMchineInfo,RegionInfo,InteractionInfo三个辅助类辅助对于状态图和顺序图的查询。

      本次作业也发现过一个bug,是对于R003规则的检查问题。

      我的实现方法就是把一个类实现的所有接口放到一个List中,如果List中有重复的元素就违反R003。同理,将一个接口继承的所有接口放到一个List中,如果有重复则违反。但我沿用了上次的一个函数

1 public HashSet<String> getAllFatherInterface() {
2         HashSet<String> result = new HashSet<>();
3         ...
4         return result;
5     }

      此函数用来求出一个接口继承的所有接口,但为了避免重复,我返回的是HashSet。但这样就会对R003的检查出问题,因为会过滤掉重复,导致检查不出R003。改也好改,只需要返回List,并且在上次调用该函数的地方将List转为Set即可。

      这次作业的UML图

      可以看出这张UML图非常庞大,主要就是因为查询的指令过多,辅助类的多了

      本次作业方法复杂度

                     

      较复杂的几个类ClassInfo,InteractionInfo,RegionInfo都是含有很多递归方法。

      总体上这两次作业较我之前的三个单元来说都有较大的提升,至少看着自己的代码不至于抓狂,而是能很快分析出来每个函数的用处,有bug出现也能很快de出来并且修复


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

  2.1  第一单元:表达式求导

      初识OO的第一个月,就面临着无比巨大的挑战。表达式求导是对于算法,思维的一个很大考验,尤其是第三次作业,引入了表达式因子。那个时候对于OO还没有什么理解,通俗的理解就和C语言的结构体类似。写出来的代码主要思想就是面向方法编程。和面向过程的思维没什么区别。

      唯一和面向对象沾边的就是把一个表达式拆分为多个项,把一个项拆分为多个因子,把一个因子归类为不同的基本因子。因此三次作业中,固定不变的总有三个类

Poly,Term,Factor

      具体到不同的作业上,三个类中的实现各不相同。

  2.2  第二单元:多线程电梯

      这一单元可能和面向对象的思维关系不大,主要就是让我们去熟练运用多线程,并且能够对多线程程序进行debug。

      三次作业的难度仍然是依次递增。从单部傻瓜电梯——单部可捎带电梯——三部可稍带电梯。

      其实这个单元如果只追求正确性的话是很容易拿到基本分数的,就比如说我。在三部可稍带的电梯中,我没有考虑三部电梯的合作,而是仍然把它们分离开,看成单独的电梯。来一个请求我也是分给固定的电梯。当然这样做的代价就是进不去A组。。。看不到大佬们的代码。

  2.3  第三单元:规格化设计

      JML语言,全称Java Modeling Language。故名思意,是为了建立一个模型,能够描述java程序的功能。也叫规格化设计。

      这一单元主要培养我们描述功能的能力。能否跳过具体实现而把一个方法或类的功能用规格化的语言描述清楚。这一点在面向对象程序设计上用的非常多,在工业设计上也经常被用到。在进行一个大项目时,不同部门的任务不同,但也需要部门间的交流,这时候能否将自己部门完成的功能描述清楚就很重要。

      这个单元让我们实现了一个地铁系统。前两次作业难点在于对事件复杂度的控制,第三次作业在于如何解决换乘。感谢讨论区的各位大佬的观点帮助我平稳度过了这个单元。

  2.4  第四单元:UML

      UML语言,全程Unified Modeling Language。UML主要用于软件需求的分析,课程组对于我们的要求就是能够读懂UML图,包括类图,状态图,顺序图。两次作业也是建立在能够读懂UML图的基础上进行相应查询。

      这一单元的架构设计相比于前几个单元是我最满意的。成功的将功能分散到各个辅助类上,但有不是面向方法编程,每个辅助类有自己的成员,方法,各司其职。这样的架构不仅看起来舒服,对于debug也是非常友好的。两次作业中我都发现过bug,但都很快的改对了。


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

  3.1  第一单元

      当时对于测试的理解主要有两点

      第一:手动构造刁钻的测试样例去hack别人。事实证明这样的方法只有在C组才能派上用场,本人在C组呆过,因此对这一点十分了解。

      第二:阅读代码,从代码中找到漏洞,然后再hack。然而一个互测屋至少7个人,在两天时间内阅读这么多人的代码显然是不现实的事情,因此我除了第一次作业看了几个代码以外,基本上都没有打开过别人的程序,一是时间不允许,二是懒。。。

      那个时候没有想过还能自己搭个评测机出来,自动去hack别人。

  3.2  第二单元

      从第二单元开始,我就开始用评测机去hack别人

      如何搭一个评测机。主要难点有两个,生成测试数据,检查输出正确性。因此每次搭评测机都不是一个人,而是一群人分工合作,最后搭出来的大家一起用。

      这一单元利用评测机找出了不少自己的bug,但在互测阶段却没有找到别人的bug。

      分析了一下,评测机生成的数据量非常大,但是有些刁钻的数据却没法做到覆盖。因为我们的测试数据是全随机的。

  3.3  第三单元

      第三单元也是评测机为主,但与第二单元不同的是这次我们在正确性检验上直接将两个人的结果进行对拍,两个人不一样就认为至少有一个人错,但两个人一样也不能确保都对。

      事实证明这样的效率很高,省去了判断正确性的复杂过程,同时从结果看,大家的强测成绩基本上都是满分。

  3.4  第四单元

      和第三单元一模一样。对拍保证正确性。


四.  课程收获

    OO这门课可能是大学生涯目前为止,除了计组以外,占用我时间最多的一门课了。由于每次作业都在周五发布,周二就要交,因此这学期基本上是没有周末的。周末要不就是在肝OO,就是在肝OS。有一次为了找bug,一直熬到凌晨4点,睡觉时天都快亮了。所以说,OO让我这个以前从来不熬夜的人学会了熬夜。当然不知道这算不算收获。。。

    最大的收获毫无疑问是编程能力,想当初大一一个学年都在学习数理知识。自以为数理基础打得扎实,学习计算机不会有什么问题。然而计组这门课给了我最大的打击。那个时候写代码简直就是噩梦。而且写出来的代码也是一堆bug。这也直接导致了计组实验的失败。OO这门课对于编程的能力不亚于计组,但这门课好就好在考核的方式,不像计组那样要求在课上2个小时完成代码并保证正确性,而是在课下给予相对充足的时间(大不了就熬夜呗)。这对于像我一样编程能力弱的人就是福音,可以有充足时间去练习敲代码,找bug。经过一个学期的历练之后,少说也编了几千行的代码,编程能力肯定有所提高。现在让我写个小程序也不会像以前一样一筹莫展。

    在面向对象思维上,收获肯定是有的,毕竟以前都没接触过OO。至少学会了OO的相关知识。也会编写OO程序,


五.  具体的建议

    第一:互测机制。

      上文提到了,一个互测屋7,8个人确实有点多,课程组的目的是想让我们通过阅读别人的代码来提高自己的代码,但阅读那么多人的代码显然是不现实的。如果能够减少一点人数,比如一个屋子4个人或3个人,这也或许就有时间去阅读别人的代码,而且这也互测的效率也会更高,不是像现在全靠评测机。

    第二:课程难度设置

      OO这门课难我是支持的,毕竟这样能够有区分度。但是不应该一上来就是最难的一部分。第一单元第三次作业就要用递归来做,有的大佬甚至用了表达式树。相反,后几个单元的难度就有所降低,特别是第三单元和第四单元。难度大不如前。其实可以将规格化的设计放在第一单元,这样或许更有利于我们对于面向对象的理解

    第三:课程评分体系设置

      OO这门课据老师说是65%作业分,25%实验课分,10%研讨课分。研讨课和实验课的设计无可厚非。65%的作业分中大部分都是强测成绩这也无可厚非。但是又有消息说是排位制,按排名高低给分。因此这就让人很迷惑,因此建议能否公布一下更明确的评分体系。如果是排位制能否让自己知道自己的排名,这样大家心理也有个数,在后面的作业中也会更加努力。

    第四:关于弱测

      个人觉得弱测不要隐藏测试点,因为弱测本来就是引导我们去找到程序中的bug,但只给个WRONG_ANSWER却不告诉你哪错了就很难受。我就是因为看不到测试数据而熬夜debug一直熬到4点才找到。个人觉得公开数据会提高效率,省下很多浪费的时间


 写在最后:

     OO这门课学下来并没有学长学姐口中说的那么恶心,助教老师们都是很和蔼,同情达理的。遇到问题问助教老师,他们都会热心的解答。

     这门课告一段落了,3个学分的课所包含的知识远远超出了其他3学分的水课。真是让我又恨又爱。  

     好了就说这么多,要预习概统了。。。

  

猜你喜欢

转载自www.cnblogs.com/buaa17231043/p/11067955.html