BUAA_OO_Unit4_总结
一、第四单元架构设计
1.第一次作业
-
在本次作业中,实现了对类图的分析功能,由于代码逻辑相对简(事实上,大多数的时间主要用于对UML类图的理解和官方包内代码的阅读中),因此,并没有采用分拆成多个Class维护的方式,而是采用在一个MyImpletation类中维护多个低级数据结构的方式。事实上,由于要求的功能说不上复杂,这些java自带的STL已足够满足我们的需求。
-
基础的数据结构的定义:
private UmlElement[] elements; private HashMap<String, Integer> stringToCount = new HashMap<>(); private HashMap<String, UmlElement> stringToClass = new HashMap<>(); private HashMap<String, UmlElement> idToElement = new HashMap<>(); private HashMap<String, String> fa = new HashMap<>(); private HashMap<String, ArrayList<String>> sons = new HashMap<>(); private HashMap<String, ArrayList<String>> interfaces = new HashMap<>(); private HashMap<String, ArrayList<String>> attributes = new HashMap<>(); private HashMap<String, ArrayList<String>> operations = new HashMap<>(); private HashMap<String, ArrayList<String>> parameters = new HashMap<>(); private HashMap<String, UmlElement> inter = new HashMap<>(); private HashMap<String, ArrayList<String>> interFa = new HashMap<>(); private HashMap<String, ArrayList<String>> interSons = new HashMap<>();
-
可以发现,其中大多数是从name,id到element的索引,还包括不同类和接口的继承实现关系,每个类和接口下的其他类型数据等等。
2.第二次作业
-
本次作业增加了对状态图和顺序图的解析(
因此简单估算发现500行不够了),于是新开了一个MyImpletationExtend类作为MyImpletation类的扩展子类来实现状态图和顺序图的解析,这样,既扩展了可以使用的内存空间(500行->1000行),也使得上次作业中的代码可以得到复用。 -
在MyImpletationExtend类的具体实现上,仍然采用和上次作业相似的方式。事实上,本次作业增加的内容并不算多,除了关键路径需要进行暴力的dfs以外,其他的新增查询功能相对而言都比较单调,因此仍然采用了上次作业中的底层数据结构实现方式。
-
MyImpletationExtend类具体的实现的数据结构如下:
private HashMap<String, Integer> interactionToCount = new HashMap<>(); private HashMap<String, UmlElement> stringToInteraction = new HashMap<>(); private HashMap<String, HashMap<String, Integer>> lifeLineToCount = new HashMap<>(); private HashMap<String, HashMap<String, UmlElement>> stringToLifeline = new HashMap<>(); private HashMap<String, Integer> statemachineToCount = new HashMap<>(); private HashMap<String, UmlElement> stringToStatemachine = new HashMap<>(); private HashMap<String, HashMap<String, Integer>> stateToCount = new HashMap<>(); private HashMap<String, HashMap<String, UmlElement>> stringToState = new HashMap<>(); private UmlElement[] elements; private HashMap<String, ArrayList<String>> edges = new HashMap<>(); private HashMap<String, ArrayList<String>> interactionSons = new HashMap<>(); private HashMap<String, ArrayList<String>> count = new HashMap<>(); private HashMap<String, String> begin = new HashMap<>();
-
可以发现,对于每一个可能用到的UML类型而言,都开了两个指针数组,一个id到count的HashMap用来计数,一个id到element的HashMap用来实现映射。
3.第三次作业
-
在本次作业中,加入了对UML图异常的检测机制,总体实现相对而言也并不复杂,就是要考虑的边界情况很多。为了不影响之前两次作业的逻辑结构,对本次作业的异常检测单独开了一个新CheckForUml类进行单独处理。
-
由于本次作业和上两次作业的时间间隔较长,因此对之前的基本数据结构的使用有些生疏,且由于数据量不大,很多可以通过暴力循环的地方都是依靠暴力循环解决的问题,因此难免带来时间复杂度的开销过大。
4.总体结构
-
总体的Uml类图如下所示:
-
在本单元的作业中,构建的代码结构非常简单,一方面确实是因为烤漆复习的压力较大,因此偷懒节约了一些时间;另一方面,简单的结构往往也能带来更加直观的理解,同时产生意想不到的bug的几率也会大大降低。因此相对而言,对自己的架构还算满意。
二、课程总结
1.架构设计思维及OO方法理解的演进
在OO课程的学习之前,由于代码的编写普遍码量较少,调试简单,因而对架构的要求普遍不高,因此难免会有代码命名随意结构环路安等诸多问题。在经历了OO课程的学习后,我明白了一个清晰的代码结构对迭代开发的重要性在四个单元的学习过程中,也收获了很多。
1.表达式
在表达式这一单元中,主要分为对表达式的解析和化简两个部分。
在表达式解析的过程中,我的核心思想和推荐思路存在不小的差异,为了更好的架构底层的加减乘运算关系,我将所有的项全表达成了同一种形式,即无论是因子之间的相加、项之间的相加、表达式之间的相加,都可以视为项之间的相加;无论是因子之间的相乘、项之间的相乘、表达式之间的相乘,都可以视为项之间的相乘。这里的项,指的是对字符串进行处理后得到的项的集合。在这种架构下,底层的数据类型是唯一的,是一种可以因子和项的通用表达。这种处理方法有利有弊,一方面,在进行常数相乘、单项相加减等简单操作时,会带来一定时间的冗余,且底层的相加减,相乘操作实现起来难度极高;但另一方面,只要我们实现了底层的运算逻辑,我们就可以实现随意的对顶层解析的结果进行运算,而不必考虑运算时数据类型变化时产生的各种差异。
在表达式的化简方面,由于更多的似乎手动化简,比较考验细心和码力,感觉有些化简实现起来并不算容易。
2.电梯
电梯算的上是java面向对象的入门课(表达式仅仅只是java语言的入门课)。在架构方面,基本上采用了生产者-消费者的模式。由输入线程、调度器、电梯线程等多个部分组成。
在这个单元中,学到了多线程编程相关的知识,也学到了不少电梯调度相关的算法,多线程让我明白了面向对象编程的真正意义。
3.JML
在这个单元的学习中,了解了JML语言的相关语法,但去除外皮之后其实就只是图论算法的复习课。
对于JML语言,它以一种数学语言的方式,明确了所需求的规格,消除了自然语言的歧义性。它通过前置条件、后置条件、作用范围等来对每个所需要的方法进行限制和描述,以一种不变的格式和状态约束形式来对每一个类进行了特定的规格化描述,使需求者和程序员之间得到充分而有效的沟通。
对于图论算法,也都算是大家耳熟能详的算法了,整体实现上来说谈不上有太大的难度,整体而言,这个单元的实现相对比较轻松。
4.UML
对于这个单元而言,学习了UML的相关知识。在这个单元中,由于每个类的功能相当有限,部分类甚至没有功能。大量的类将整个项目碎片化并不见得有利于作业的完成,因此,这种时候换用一个更综合的架构在码量和思维量上都是一个不小的优化。这个单元也提醒了我们,要领会面向对象的思想,而并非是对着繁琐的架构照搬照抄。
2.测试理解与实践的演进
1.表达式
- 进行了各方面的手动测试:
1.基础功能测试:测试好简单的基础功能,能通过上次的强测数据和本次中测中可显示的测试点(找已经过关的同学贴贴),然后简单的debug后提交通过中测。
2.优化功能测试:每写好一个优化模块就进行测试,多和同学讨论数据构造,找到足够强的数据完善自己的代码,优化过的地方一定要着重测试。
3.极限数据测试:大常数和0常数的测试,sum上下界的测试,极限数据运行时间的测试。。。
2.电梯
- 进行了一部分的自动化测试,这一部分借助了同学的评测机,保证了程序的正确性。
- 进行了相对广泛的手动测试:从各种极端数据到压力测试数据,以及超大规模的随机数据,保证了程序的高效性能,也在互测中得到了较满意的成果。
3.JML
由于大家的代码基本都是按照JML语言的描述编写,因此正确性错误出现的概率很低。在互测中出现的bug也都是严格按照JML语言描述实现的复杂度极高的TLE。
在这个单元中,由于正确性检验仅仅需要对拍就可以实现,检测程序的实现难度大大降低,因此写了一点简单的自动评测,效果还算可以。
4.UML
烤漆压力过大了,基本三次代码作业的完成都是踩线完成的,再加上没有互测,导致并没有经过非常完善的测试,不过相对而言,结果还算说的过去?
总结
在OO课程的学习过程中,也逐渐养成了一套系统的OO编程的测试方法。
在程序完成的过程中,需要进行部分功能的测试,以仅最大可能保证实现的函数没有问题。以尽可能减少后续测试时debug的难度和所de的bug数量。
在项目完成后,需要自己进行简单的功能测试,尝试各种可能的简单的样例形式,并检查输出结果分析其时候合法。之后依靠评测机自动测试,确保总体上不会出现效率过低和正确性错误等显著异常的问题。这里需要结合具体单元具体分析,以保证自己程序的正确性和覆盖率。
最后需要进行满数据和边缘数据的特殊构造和检测,在这部分往往能发现一些之前自己忽略的问题,弥补自己的短板,提高自身测试的全面性。
3.课程收获
- 学会了java语言的基础语法,学会了很多新的算法,提高了自身的算法能力。
- 学习了面向对象的思想,体会到了面向对象编程的魅力。
- 在和同组同学的讨论过程中,认识到了很多新的朋友,也充分认识到了自己的不足。
- 学会了系统地测试自身程序的方法,提高了思维的严谨性,对自动评测的原理有了一定的了解。
4.改进建议
- 对于第四单元的指导书,希望适当解释下每个类的功能和函数作用,整体的代码量有些过大了,通读整个项目文件会浪费过多无必要的时间。
- 希望预习课程不仅仅有对java语法的学习,对多线程、UML、JML都应该有所涉及,哪怕只是简单的科普,也为学生的后续预习提供一个明确的方向。
- 希望适当降低实验课的难度,部分实验课(比如说刚刚接触多线程)的难度对尚没有编程经验的学生而言有些难度过大了。