OO 第四单元总结

第四单元OO总结

本单元架构设计

   本单元需要实现UML模型的存储与查询功能,主要的难点在于理解UML模型、设计存储结构、选择查询算法三个方面。主要架构分为第十三次作业与第十四次作业两种架构(第十五次作业仅仅是在第十四次作业上增加了查询方法)。

  第十三次作业仅有类图以及相关查询,第十四次作业在类图之外包含顺存图与状态图模型,因此是第十三次作业的扩充。

  第十三次作业考虑到后续的扩展(以为之后会在类图方面做更多的存储与查询),采用的是类似UML类图架构的树形设计与存储。新建了:MyClass,MyInterface,MyOperation,MyParameter,MyAttribute几个类用于存储相关信息。在MyUmlInteration中,考虑到可能出现重名类,使用两个HashMap存储所有的类,一个是id2Class,一个是name2Class。当获取到新的类时加入id2Class,并检测name2Class中是否包含这个name的Key,如果已经包含,就把这个name对应的value置为null。如此在查询时根据类名获取类,倘若获取到null就知道是有重名的类了。对于这次作业中其他可能触发重名异常的地方也使用相同的方法处理。

  在处理输入时,考虑到输入之间可能存在相互依赖关系,因此对输入的UmlElement按照依赖关系进行分批处理,首先处理UmlClass,UmlInterface,UmlAssociationEnd类型的输入,然后处理UmlParameter,最后处理其他类型。这样就能避免类中的引用对象已输入但还未处理的情况。

  十三单元存在两个查询操作直接实现复杂度达到o(n^2),一个是类的操作的参数类型,另一个是类实现的全部接口。关于类操作的参数类型的主要问题在于可能出现重复的类操作,因此需要对所有的参数组合进行比较,比较麻烦。采用转化为字符串进行比较的方法。转换字符串的工作可由MyUmlOperation类自行完成,MyUmlOperation类将每个参数类型转化为String后装载入一个ArrayList中,然后对ArrauList进行排序,最后拼接上“return”+返回值类型就形成一个包含所有参数信息的String,在MyClass中获取到所有同名操作的参数String后将他们加入一个HashSet中,最后根据HashSet的长度与同名操作数目是否相等来判断是否存在参数集相同的同名操作。关于类实现接口的方法,采用深度优先搜索方法,稍有不同的是在搜索时携带一个数组表示已经搜索过的节点Id,不重复搜索以查找过的节点,因此每个节点最多被查找一次,复杂度为o(n)。

  第十四单元由于引入了顺序图与状态图,因此架构需要在第十三次作业的基础上做一些扩充。考虑到查询效率,这次的架构实现我新建了更少的类,更多的将Uml图的信息转化为类之间的关系,形成一种更接近图的结构。对于顺序图新建了MyUmlInteration,MyUmlLifeLine两个类,对应顺序图中Interation与LifeLife两个包含较多信息的结构。状态图方面新建了MyUmlStateMachine与MyUmlState两个类,两个图的实现类都是图容器加图节点的考虑方式,将其他信息化为图节点之间的关系存储于图容器中。因此大大减少了类的数量,提高了查询的速度。

  第十五单元增加了Uml规范的检测,即新增了八个查询方法。其中R002不能有循环继承与R004不能重复实现接口是我重点考虑的对象。关于检测循环继承我的思路是:采用不重复的方式获取该接口(或类)的所有父类,然后比较所有父类中是否包括自己,如果包括,则将自己加入R002抛出异常的信息中。对于每个类的查询操作复杂度不大于o(n),总的复杂度不大于o(n^2)。对于R004采用递归的方式,先获取父类实现的所有节后,然后加上自己实现的所有接口,如果有重复则将自己以及自己的所有子类加入R004异常的信息中。最终设计出现了一些bug,主要是考虑到一个接口本身不会继承同一个接口两次(讨论区看的),因此采用的是HashMap存储接口继承的接口,所以对于A extends B,B这种情况无法做出正确的重复实现判断。以及在阅读R005:类图元素名字不能为空的要求时错误的将类图元素理解为类的元素,导致没有判断接口名字为空的情况而wa了。

  总的来说本单元是一次基于Uml图结构理解的图建模任务。实验的重点与关键在于Uml模型的理解,在图的存储于查询方面并未为难我们(也是因为考期手下留情QWQ)

结构设计与理解的演进

  第一单元实现多项式求导,创建类时类的功能非常明确,就是需要具有求导与表示自身的功能,因此该单元对于类的设计主要关注内容存储方面。即用什么方式能在类中完整的表示出多项式的信息并能对他进行求导、打印、甚至化简。不同的数据结构下求导与表示的实现实现难度大不相同。

  第二单元实现电梯模拟运行,主要的考虑在线程的划分即职能的划分。划分类考虑的更多是功能方面的需求,需要考虑的是类中属性与方法的协调性与内聚性。内聚性好的类设计可以使线程之间的交互减少,线程之间的耦合关系减弱,更不容易出现bug。在新建线程时必须充分考虑该功能采用额外线程的必要性,倘若将本应属于一个线程的任务划分给两个不同的线程,就会导致线程之间非常频繁的同步交互,使设计变得非常复杂。因此,相互之间联系紧密并且不会导致阻塞的功能应当尽量放到一个线程中实现。

  第三单元根据JML规格实现人际关系网络,官方包已经帮我们搭建好了主要的代码架构,划分好了函数。我们需要做的就是建立合适的数据存储图来高效实现需求的方法。当然所有的实现都是在阅读JML规格要求之后的步骤。并且在本次试验中,还需使用一些算法来提高方法效率。通过本次实验,对于全局数据存储与查询以及图结构有了更深的理解。

  第四单元我们需要基于对UML图的理解完成UML图的存储与查询功能。输入输出的格式与方法已由官方包提供,主要的设计在于内容的存储方面,即用什么样的类来存储输入的UML图属性。考虑到UML图天生具备的树状结构,可以采用树形结构来设计与存储;也可以从UML图中抽象出图结构,根据节点与节点之间的关系来存储。

测试理解与实践的演进

  四个单元下来,关于测试的观念经历了:不测试——构造测试——程序随机生成测试——程序随机生成特定数据测试——根据方法的不同执行状态的模块化测试;的转变。最开始写第一单元时,不进行测试导致提交上去出现BUG后无法定位错误,花费很长的时间来漫无目的的寻找错误。于是开始尝试在可能出现问题的地方构造数据去“发现错误”,再根据错误数据运行的路径定位错误代码。也就是说最开始测试的目的是为了更方便的定位错误,节约编码时间。

  第二单元开始,除了通过数据进行正确性检验并修正正确性外,因为有时间的限制,电梯运行的效率也变得十分重要。于是测试又多了检验电梯在各种情况下的实际运行情况的功能。通过随机生成的大数据的运行能发现一些电梯调度的问题或者电梯策略的不完善,并及时给予改正。当然极端的数据还是需要在一定特定条件下随机生成,也就是构造与随机相结合的方式。通过了各种角度的随机测试,电梯的功能与完备性就有了比较好的保障。

  第三单元由于方法有了明确的划分与JML规格的帮助,可以非常方便的使用Junit进行模块化检验,对于方法的每种输入情况分别提供数据并检验,能全方位的检测方法在所有情况下的运行是否符合预期,基于方法的检测在发现问题后能非常容易的定位问题并及时解决,并且在代码量不断增大的情况下均有相对稳定的测试工作量。能很好地保证代码的可靠性。

课程收获

  OO课程我认为是非常有意义并且非常有意思的一门专业课程,经过OO课程一学期的训练,我基本形成了面向对象的思想,养成了划分类,划分方法的习惯,培养了分解问题的能力。并且OO课程教会我们的多线程相关知识,JML规格与UML模型,都是将来工作中相当有用的知识技能。每周几百行上千行代码的训练显著提升了我的代码编写能力,也建立了我面对与解决复杂问题的信心与设计能力。总的来说,在OO课程的锻炼下,我的核心专业能力与专业素养得到了很大的提升。

改进建议

  • 第一单元工作量太大,当时由于架构问题(每次作业一次重构),每次作业都需要一天以上的时间才能完成,有时甚至两三天都在写OO,压力山大,是否可以稍微减轻一些第一单元的工作量。

  • 感觉每个单元结束后,可以尝试公布一些性能表现的非常优秀或者架构设计很好的同学的代码供我们参考学习。

  • 希望第三第四单元没有互测环节时能更早公布强测结果,方便bug修复。

posted @ 2021-06-24 10:18  ffgsq  阅读(100)  评论(0)    收藏  举报