BUAA_OO第四单元总结(类图)

1. 架构设计

1.1 第一次作业

第一次作业要求实现UML类图的查询功能。在维护类图的时候,采用了以类(Class)为结点的构建方法,即将Class处理成以键值对<\id, Class>存储在HashMap中。将类图中的其他元素看成是Class中的属性,这样能够更好地进行层次化的类图构建。
关于层次化,本次架构按照层次,共有如下几类:

  1. MyUmlGeneralInteraction:实现了接口UmlGeneralInteraction,是各类查询功能的入口
  2. MyModelGraph:类图类,用于构建和维护类图,其中如下元素:
    • MyClass
    • MyInterface
  3. MyClass:存储类的各种属性和关系,有如下元素:
    • UmlAttribute:存储类的属性
    • MyOperation:存储类的方法
    • UmlAssociationEnd:存储类的关联关系
    • MyInterface:存储类实现的接口
    • MyClass:存储类的父类
  4. MyInterface;存储接口的各种属性和关系,有如下元素:
    • MyOperation
    • UmlAssociationEnd
    • MyInterface:存储接口继承的接口
  5. MyOperation:存储方法,有如下元素:
    • UmlParameter:存储方法的参数
       

至此,类图的所有信息都以层次化的方式存储到了MyUmlGeneralInteraction。

关于采用的数据结构,观察实现的功能,其中ClassNotFoundException, ClassDuplicatedException,AttributeNotFoundException, AttributeDuplicatedException等异常的处理,以及相关的查询是以类,属性等的名称来进行查询的,而在类图中是以id作为唯一标识的,因此需要以id来进行存储。而这样会导致以name查询名称重用,名称是否存在,取得相应元素,效率很低。因此考虑将name和id进行维护,在查询的时候将name转换为id。

为此,在实现上,为Class,Interface,Attribution等元素维护了HashMap<\String, ArrayList<\String>> nameMap,用来将组成name和id的一对一至一对多映射,方便异常判断,并可以将name转换为id,在以id为键值的HashMap中方便地取得元素。

在关联关系的表示上,采用在Class或Interface中维护对端的UmlAssociationEnd来进行表示的,而UmlAssciation只是用来明确UmlAssociationEnd应该向哪个结点分配。
同时,由于采用的是层次化的类图构建,而读取到的Uml元素可能并不是按层次化的顺序,因此可能出现,一个更底层的元素所依赖的上层元素还没有出现时,需要存储这一底层元素的情况,出现空指针异常。在类图即MyModelGraph初始化的时候是按照层次由高到低一层一层进行初始化的:

  1. 首先初始化类图结点MyClass和MyInterface,另外初始化MyOperation存储到相应结点,UmlAssociationEnd方便后续使用
  2. 初始化UmlAttribution存储到结点中,初始化UmlParameter存储到MyOperation,读取UmlAssociation以存储上一层的UmlAssocationEnd到结点,读取UmlInterfaceRealization,UmlGeneralization存储相应的MyClass,MyInterface到相应的结点。

1.2 第二次作业

第二次作业实现了时序图和状态图的查询,依然采用了层次化的构建方式,在时序图中以UmlLifeLine为结点,在状态图中以UmlState为结点,维护了图
关于时序图层次化:

  1. MyUmlGeneralInteraction:实现了接口UmlGeneralInteraction,是各类查询功能的入口
  2. MyInteractionGraph:时序图类,用于构建和维护时序图,有如下元素:
    • MyInteraction
  3. MyInteraction:存储和维护每一个交互图,包括:
    • MyLifeLine
  4. MyLifeLine:交互图的结点,包括:
    • UmlMessage
      在实现上,依然采用了数据结构HashMap<\String, ArrayList<\String>> nameMap,方便查询和异常处理

 
关于状态图层次化:

  1. MyStateGraph:状态图类,用于构建和维护状态图,包括:
    • MyStateMachine
    • UmlTransition
  2. MyStateMachine:状态机类,包括:
    • UmlPseudostate:起点状态
    • UmlFinalState:终点状态
    • MyState:状态结点
  3. MyState:状态类,包括:
    • UmlFinalState
    • UmlPseudostate
    • UmlEvent
    • UmlTransition
      为了方便查询算法对所有状态的统一管理,将起点和终点统一交给了Mystate来管理,实现了三个重载的初始化方法:
  • public MyState(UmlState state, HashMap<String, UmlTransition> transitionMap)
  • public MyState(UmlFinalState umlFinalState, HashMap<String, UmlTransition> transitionMap)
  • public MyState(UmlPseudostate umlPseudostate, HashMap<String, UmlTransition> transitionMap)
    实现上同上。

1.3 第三次作业

这一次主要是对所构建的类图进行合法性检测。这一单元的作业,层次化相对容易,同时考虑到了可扩展性的问题,在每个层次中的类中维护了足够多的信息,因此在检查合法性上,相对容易,主要在循环继承,重复继承方面需要谨慎考虑。总之是三次作业中最容易的一次。

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

2.1 第一单元

层次化这一单元,第一次接触到了面向对象构造,这一单元给人留下了非常深刻的印象,现在回看,这一单元的难度也是很大的,由于嵌套等形式的存在,使得这一单元的层次化工作相对难以实现。
在最初第一次作业的时候,思维依然没有跳出过去面向过程的编程方式,只是将过去按照函数进行封装改为由类进行封装的模块化设计,这也导致了在第二次作业的时候进行了面向对象所有作业中最痛苦的重写。
而在之后的作业中,慢慢感觉到了面向对象中实现,继承和多态的特性,对于这些特性的运用,初步感受到了面向对象的便利。
总的来看,本单元的作业,由于第一次接触到面向对象的思想,并不了解架构为何物,所以也没有考虑太多架构设计。类与类之间的耦合是非常紧密的,同时采用了大量的反射特性和if-else级联,其实返回来阅读是很痛苦的lol。
本单元对OO方法的理解,也许就停留在了利用面向对象的语言特性,简化编码(硬编码)。以及通过类进行封装,达到模块化设计

2.2 第二单元

这一单元进行的是多线程编程,作为多线程死锁选手,debug的过程是非常痛苦的,尤其是第一次不知道多线程调试需要检查哪些问题,也不知道JProfiler等工具的运用,一个锁顺序问题,可以卡一天。
但是,其实本单元最重要的内容是关于架构方面的设计,课堂上讲授了生产者消费者模式,发现设计模式对于架构设计可以提供非常好的实践,所以在课下也学习了其他模式,例如适配器和单例模式。
本单元由于多线程的存在,各个模块的时间线和功能都是独立的,耦合度相比第一单元低了很多,因此很方便理解面向对象设计。
本单元对OO方法的理解,有了一些自己的理解,作业中有生产者,托盘,消费者,它们之间具有自己独立的功能,维护自身的数据结构,对于其他类仅仅暴露自己少量的接口,以实现解耦,达到良好的扩展性。

2.3 第三单元

这一单元的JML,让我有了架构优先于代码编写的认识,对于一个工程,首先需要有明确的需求,其次要由架构设计自顶向下地进行模块的规划,考虑每一部分地功能以及可扩展性,而忽略使用的数据结构和具体的方法。最后,在我自己填充提供的框架的时候,深感对于具体代码的填充采用自底向上的方式,可以更加方便地考虑自己要采用的数据结构。

2.4 第四单元

这一单元的UML类图,自己在前面三次作业中对层次化有了新的认识,因此从一开始在编码的时候,无论是数据结构还是架构,都在考虑随后的可扩展性。生成的UML类图,相比之前,肉眼可见的顺眼(有了层次)。

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

在测试方面的演进主要集中在第一单元上,这一单元非常迷信于自动化的随机测试,以为测它个上千上万次就万事大吉了。但是由于采用的是随机测试,而在测试中覆盖率才是最重要的影响因素,对于极端数据几乎难以进行有效覆盖,因此互测中被各类奇怪的数据进行了Hack。
而后来对极端数据,主要是手动生成,但是这种方式难以对程序做到100%的覆盖率。
另一方面,为了尽量将bug扼杀在摇篮里,减少在最终测试中隐藏的虫子,Junit可以对方法,模块进行覆盖测试,减少了模块内部的bug,能够有效加快测试速度,错误率也会低很多。但是自己在编写测试的时候,需要仔细考虑,由于这一点,对所有的模块,方法都进行覆盖测试,是不现实的,需要首先筛选出算法复杂之类的模块,进行测试,同时兼顾效率和准确率。
而在大的方面,所有的OO作业都主要以python进行测试数据生成和对拍。python提供的大量库可以尽量保证python实现功能的正确性。

4. 课程收获

首先,在截止目前的所有编程相关的课程中,面向对象的课程体验毋庸置疑是最好的,课程和作业紧密相关,每个单元都有一个聚焦的重点。
面向对象设计与构造,首先最重要的一点就是面向对象的思想,在课程过程中,从面向过程的编程思想,逐渐过渡到了面向对象的编程方法,最后发现,其实两者之间并不是割裂的,在面向对象的过程中,其实面向过程的方式可以用于在模块内部方法的层次化
另一方面,就是设计与构造了,课程让我开始逐渐知道在实际实践过程中,架构设计才是其中更加重要的一方面。合理的模块和层次设计不仅可以满足良好的可扩展性,另一方面其实也可以简化代码的工程量。
其次,在最后一个单元的官方包里的pom.xml引起了我的注意,在查询以后才知道这是Maven的配置文件,因此也去学习了一些关于Maven项目管理的内容,通过学习,不仅可以将Junit,打包等工作统一起来。更重要的一点是Maven可以把java很多内容串起来,给面向对象或java的进一步学习提供了一个方向。

5. 改进建议

面向对象的课程设计相比其他课程已经比较完备了,如果有建议,大多就是些小修小补:

  1. 可能在学习曲线上还是稍微有一些陡峭,第一二次作业的难度和其后两次作业的难度,形成鲜明的对比。我觉得可以考虑将一部分多线程和层次化的具体实践下放给一个预习模块,或者在预习模块提供一个实践例子,先试试水(
  2. 在预习上,也可以提供一些关于测试的设计练习
  3. 作业和训练都有良好的反馈机制,是否可以考虑实验提交或者结束以后给一个反馈,方便知道自己的问题。
posted @ 2021-06-26 12:35  HyperCarrot  阅读(59)  评论(0编辑  收藏  举报