OOP第四期作业总结

目录

UML系列作业设计架构

Project13

Project14

单元架构设计

第一单元--表达式求导

第二单元--电梯系列

第三单元--jml系列

第四单元--uml系列

测试理解与实践的演进

第一单元--表达式求导

第二单元--电梯系列

第三单元--jml系列

第四单元--uml系列

课程收获

给课程提三个具体改进建议

UML系列作业设计架构

Project13

任务为实现一个UML类图解析器UmlInteraction

类图如下:

由于不清楚指令是否按照期望的顺序执行,因此分为三层加入指令:

其中白色为第一层;粉色为第二层;蓝色为第三层。

 

 

思路如下:

1.我将一个类图作为基本单元进行存储,从要查询的指令出发,分别储存

 1 //名字到属性的映射
 2 
 3 private HashMap<String, ArrayList<UmlAttribute>> nameToAttri
 4         = new HashMap<>();
 5 
 6 //指令id到操作的映射
 7 private HashMap<String, OperatElemt> idToOpera
 8         = new HashMap<>();
 9 
10 //此类中不是private的属性集合
11 private ArrayList<UmlAttribute> notVisibToAttri
12         = new ArrayList<>();
13 
14 //属性名字到各类可视性数量的集合
15 private HashMap<String, HashMap<Visibility, Integer>> nameToVisibForNum
16         = new HashMap<>();
17 
18 //各类操作类型的集合
19 private HashMap<OperationQueryType, HashSet<OperatElemt>> typeRequireToNum
20         = new HashMap<>();
21 
22 //关联的类id集合
23 private ArrayList<String> idToAssoc
24         = new ArrayList<>();
25 
26 //实现的接口集合
27 private ArrayList<String> idToInterface
28         = new ArrayList<>();
29 // UmlClass || UmlInterface
30 
31 private UmlElement rawElement;
32 
33 //类名
34 private String className;
35 
36 //继承的父类id集合
37 private ArrayList<String> fatherId;
38 private int sumOfAttri = 0;
View Code
  1. 由于需要判断操作的类型:是否有返回值,是否存在参数。因此我单独为操作设置一个类OperatElemt,里面存有返回值和参数类型的两个属性,具体判断如下:
 1 public OperationQueryType addType(UmlElement umlElement) throws Exception {
 2     if (!(umlElement instanceof UmlParameter)) {
 3         throw new Exception("not UmlParameter");
 4     }
 5     if (((UmlParameter) umlElement).getDirection().
 6             equals(Direction.RETURN)) {
 7         returnType = OperationQueryType.RETURN;
 8         return returnType;
 9     }
10     attribType = OperationQueryType.PARAM;
11     return attribType;
12 }
View Code
  1. 由于接口类图和类图很相似,区别在于接口实现多继承。我们的作业中由于不怎么涉及二者区别,因此我没有采用接口类继承MyClass类的思路,而是在MyClass类中fatherId属性设置为ArrayList类型。至于为什么设置为Arraylist而不是HashSet呢?开始我的想法是设置为ArrayList类型使用迭代器的时候比较方便,后面舍友发现如果使用HashSet会出现bug,因为如下图是判断为重复继承:

但对于此点我存有疑惑,因为在java8中并不能这么写。

  1. 利用umlMap类与UmlInteraction进行交互。为了加快查询速度,设置缓存
1 private HashMap<String, Integer> nameToClassAssoCountCache
2         = new HashMap<>();
3 private HashMap<String, ArrayList<String>> nameToClassAssoNameCache
4         = new HashMap<>();
5 private HashMap<String, ArrayList<String>> nameToClassInterfaceCache
6         = new HashMap<>();
7 private HashMap<String, String> nameToTopParentCache
8         = new HashMap<>();
View Code

一点思考

在本次作业中我认为自己还是比较好地实现分层思想,代码量上确实比其他同学多一些,类设置也多一些。在进入增加元素操作时我会先进行判断是否是自己期望的类型,不然便会抛出异常以便后期检查,我觉得这是自己进步的一大方面。虽然自己写的程序设置已经是从外层判断到是该类型才会进入相应操作。

类行数最多也只是250左右,在行数减少方面也是有所改变。

Project14

顶级类图:

 

Package umlsequence类图:

 

Package umlstatemachine类图:

 

Package umlclass类图:

 

本次作业有了第一次的基础,在类图设计上大体相似在交互类和基本单位中间设置一个类集合作为中间桥梁进行联系。

思路如下:

  1. 建立好umlmapumlstatemachineumlsequence三种图及相应查询。
  2. 利用Dispatcher类将指令分类,分别传入三种类图的集合:
 1 if (isUmlSequence(umlElement)) {
 2     umlSequence.addElement(umlElement);
 3     //System.out.println(umlElement.toString());
 4 } else if (isUmlSm(umlElement)) {
 5     umlsm.addElement(umlElement);
 6     //System.out.println(umlElement.toString());
 7 } else {
 8     umlMap.addElement(umlElement);
 9     //System.out.println(umlElement.toString());
10 }

 

  1. 在各类集合中处理好关系后构建各类图交互:
1 myUmlInteraction = new MyUmlInteraction(umlMap);
2 mySequenceInteraction = new MySequenceInteraction(umlSequence);
3 mysmInteraction = new MysmInteraction(umlsm);

 

  1. 最后传入GeneralInteraction中进行各类查询:
 1 public MyUmlGeneralInteraction(UmlElement... elements) throws Exception {
 2     Dispatcher dispatcher = new Dispatcher();
 3     for (int i = 0; i < elements.length; ++i) {
 4         dispatcher.addElement(elements[i]);
 5     }
 6     dispatcher.renewInteraction();
 7     myUmlInteraction = dispatcher.getMyUmlInteraction();
 8     mySequenceInteraction = dispatcher.getMySequenceInteraction();
 9     mysmInteraction = dispatcher.getMysmInteraction();
10 }

 

  1. 单纯为每种类型的图构建并不难,架构思路主要是预判应该放在哪个地方?这个问题我仔细思考后决定放在MyUmlIneraction即第一次作业的交互中。因为我们发现这三种判断都是基于类图的,因此我需要与类图集合UmlMap联系起来,这样保证预判只会与Umlmap这层有联系,并且我可以在预判过程中构建好每个类的终极父类和实现的接口集合,在查询的时候直接判断查询,不需要重新操作一番。一举两得。

最后说明一下我预判的思路:

规则1

我在每次加入属性的时候就进行判断,并在umlmap类中设置breakRule002集合,在每次加入AssiocatioinEnd的时候也进行判断是否出现属性重名现象,最后是迭代为每个类加入关联类时是否出现End名称与属性名称重复现象。

规则2

分成类与接口两种判断。

对类图,由于只能单继承,因此每个环都是相互独立而不影响,遍历类,如果发现A父节点回到已有的父节点B,就将重复的节点B到现有节点A全部加入集合,并且设置标记,后续遍历时只用判断没有标记过的节点即可。

对接口:由于多继承,采用深度遍历形式,思路与上述相似,如果父节点是当前查找节点便加入集合,区别在于不能找到一个环,只能对所有接口节点都进行遍历。如果想采取加环模式,可采用讨论区里面提及的tarjan算法自己模仿写了一次,但怕写错没敢用。

规则3

由于第一次作业中我们实现查找类实现的接口集合的指令,因此这次沿用上次思路,只需要判断实现的接口中是否存在重复接口,如果出现则说明这类有重复实现接口;如果当前查找的类父类为重复实现,则自身也是重复实现;接口类似。

一点思考

在本次作业中,由于沿用第一次作业的设计思路,加上助教们简化指令与类图,实现起来并不困难。这次作业也算是我思路较为清晰的一次作业,很多人认为这次作业写的代码很难看,确实,当我进行形式化检验的时候由于采用分层结构,需要一级一级检查;当我进行优化时需要将之前测试的数据都测试一遍以防出错,所花费的时间还是很多的。并且如果没有浅显易懂的属性命名、操作命名或者是注释的话,自己可能都要很长一段时间理解之前写过的函数或者属性是用来做什么的。幸好现阶段还是能让自己读懂所写代码。因此我也希望自己通过学习标程体会其中的设计架构,提升自己。

单元架构设计

第一单元--表达式求导

由于不会递归下降法实现表达式--因子的分离,只好采用大正则的方式拆分各项判断所属类型,进行求导,思想上还是从过程进行考虑。从类图中可以看到我的思考过程:得到输入、检查格式、构建表达式、分离表达式操作、两种类型求导操作、最后打印输出。

 

oo方法理解I

经过第一期的三次作业,自己面向过程的程序vs同组面向对象的程序。我看别人的代码时,面向对象的代码会有一种逐级分层的感觉,让人更加明白大体框架,至于内部的实现方法尚一时不能看出来。面向过程的代码能让人较快理解其中的实现方法,但是大体的框架一般难以清楚。

第二单元--电梯系列

第二期作业中,由于三次作业思路类似,因此并不需要怎么重构。感觉课程组也在帮助我们理解面向对象的含义。对一部电梯,有处理--调度--电梯运行三级结构,采用生产着--消费者模型,调度器为单例模式。当然,由于是多线程,需要考虑每个线程的交互过程,灵活运用notifywait。不过,不太清楚工厂模式的用法,因此感觉第三次作业代码冗余繁多。

oo方法理解II

第二期作业中,类与类之间的关系会比第一单元更加清晰一点。当然,由于这期作业中交互的消息(乘客需求)比较明显,因此我们感觉上理解面向对象更加深入一些。这期作业中,我学习到oo的一些设计模式:工厂模式、单例模式、简单工厂模式、抽象工厂模式等等,其中我照葫芦画瓢地用了工厂模式和单例模式。很难想象如果采用面向过程的思路如何完成本期作业。

第三单元--jml系列

这期作业充分感受到得到清晰需求的便捷。

本期作业从路径开始逐步构建不同类型的图,充分让我体会到重构的乐趣。由于图很多涉及到查找,加上CPU时间的限制,我开始了HashMap的使用旅程,并且采用缓存结构存储已查询的数据。从path->Container->Graph->System,逐步构建地铁系统。本期作业虽然最后一次写炸了,但是整体思路还是比较清晰的,最后重构算法的时候也比较容易修改。

 

oo方法理解III

这期作业标程有开放,深深感受到自己代码的丑陋:-)在标程中学习如何面向对象写程序,感触真的很深,不仅仅是设计架构、在代码风格、算法技巧上也学到很多。本单元通过jml的训练,我发现规格是需求者和开发者间最好的无二义性的语言。同时也学习了设计模式的六大原则,帮助自己改善代码编写风格和提高设计想法。

第四单元--uml系列

这期作业中,从类图--集合--交互三个层面进行思考,层级从小到大,中间层为容器。但是和周围同学讨论发现,很多人采取建树方式封装数据结构,自己的设计还是不太合理,没有什么成型的结构,查询方式有些面向过程。

 

oo方法理解IV

本期作业中,uml的结构理解比较清晰。自己编写的程序看起来比较分层,会有一种在面向对象编程的感觉。但自己在画图方面能力比较欠缺,感觉除了按照作业要求画图之外没有学习到uml与程序之间的联系:-(

测试理解与实践的演进

第一单元--表达式求导

第一单元我所采取的是自行编写数据以及小伙伴间share数据的方式,在前两次作业互测中还采取阅读同组同学代码来找bug,结果是感觉别人写的代码真好,自己啥bug也找不出,随手写数据还能hack到别人。第一单元结束时有同学分享如何编写对拍器,当时的自己能力太弱,没有对此上心。后期当自己写出对拍器的时候已是jml第三次作业在C组,bug太多根本就对不起来。

第一期作业自己代码在风格上还是比较不太好的,体现在命名、类行数、类名以及设计技巧上的拙劣,在第一次作业中努力学习他人代码中如何灵活运用正则表达式进而改进自己的代码结构。

第二单元--电梯系列

第二单元的测试重点会从自己的设计架构中寻找边界条件,包括电梯运行楼层、人数限制、开关情况等等。当然,在第二次作业中本想着优化一下结果失败了反而炸了两个点,我的电梯成功地突破楼顶上到17楼&&下到-4楼,实际上是我误将一条语句当作无关紧要而删除。在自己编写的测试数据中也没有体现出来,感觉自己的数据还是没有覆盖自己的设计思路。同时同学的评测机由于自身python环境没有搭建好的缘故没有用上。

第三单元--jml系列

第三次作业体验junit单元测试,但是实际上测试数据还是要自己编写的。有同学贡献数据生成器,但是由于生成的比较随机因此用途不大。主要采取的是形式化验证,根据规格检验设计思路的正确性。比较耗时间

本期作业完成后感觉对继承理解更加深入,但是程序的高内聚低耦合还是没有很好做到,以及数据结构技巧的不熟练充分暴露,迷失在复杂的算法中。

第四单元--uml系列

第四期作业中需要自己编写类图进行生成数据,因此我和同学采取覆盖性画类图写测试样例,全部情况都考虑到来进行测试。同时对自己的代码进行形式化检验,但是形式化检验在第二次作业中就真的需要花费很长时间。特别是在进行优化的时候需要将全部过程再检验一次。

本单元感觉上是我架构比较清晰的一期作业,我发现分层对逻辑清晰还是比较有帮助的。

课程收获

本学期四期的oop训练,从什么是面向对象开始到自己写出比较满意的代码。从设计模式的学习到自己实践运用,同时用设计原则分析自己代码的不足。13次作业中强测出现3次bug:分别是电梯的第一次和第二次,jml的第三次;第一次的bug是由于指令只设置30条,没有考虑终止指令是额外一条:(第二次则是粗心没有认真思考是否要删除代码,最后一次则是在拆点中迷失自我,出现大面积tle。我在这里真心佩服那些没有出现bug的同学!

在这门课程中,收获如下:

  1. 在编写代码的风格上有所改进,更好地注意行数、命名、函数间关系。在互测环节阅读他人代码能力增强,并且在阅读过程中学习其他同学好的编写风格,改善自己的代码风格。
  2. 自己deBug的能力增强,写Bug的数量减少,高了代码初期的准确性。在测试环节知道用形式化方式进行逐语句检验,这是最基本也是最重要的检测方式。同时也学会写基础对拍器,和同学的数据进行比对,提高自测效率。
  3. 自学能力有所提升,完成一次作业可能会用到新的数据结构,比如hashMap的学习,灵活运用java语言中已有的结构,减少重复造轮子以及用错轮子的概率。
  4. 将课堂上老师所说知识点加以运用。(但我觉得自己在课堂上没有记住多少老师强调要看的东西)
  5. 初步理解线程、jml设计规格、uml模型表达。

给课程提三个具体改进建议

  1.我认为课堂知识点不太能和作业联系起来。课后实践时感觉PPT上课参考的资料太少,课堂效率不高,同学们普遍认为不能从课堂上学到什么。因此,我希望日后课程组能够在编写PPT的时候更加浅显易懂或者与作业更加契合一些。

  2.可以在发布作业的时间上更加及时一点吗?感觉有时候没有按照预期发布时间来进行,虽然总体时间没有什么变化,但还是会影响到大家的安排。还有内容上面,虽然我们可以理解助教们在首次发布指导书可能有一些地方没有考虑好,但还是希望助教们能够尽快解决出现的问题,毕竟编写程序这事,可能会涉及到同学们重构的问题,以及某些同学提交次数受限的问题。

  3.每期作业结束后都可以公开一下标程吗?想学习一下标程的设计架构、代码风格、数据结构等方面。还有评测机机制也可以公布一下吗?当时我做多线程电梯的时候,真的不知道为什么自己的代码到评测机上就跑不出来,自己在本地用命令行测试都没有出现过tle的情况,实在难以找bug。最后,非常感谢助教们和老师们对我们这届评测机制上的改进!辛苦您们了!!!

猜你喜欢

转载自www.cnblogs.com/zt17373358/p/11068956.html