BUAA OO 第四单元总结 & 课程总结

1. 第四单元架构设计

第四单元的主要任务是实现对UML文件的解析和静态查询,所查询的对象包括类图、顺序图、状态图三类。

1.1 三种模型图简介

类图是描述面向对象设计的经典模型,主要聚焦项目中类、接口、属性、方法以及他们之间的关系。

顺序图是描述类、线程之间协作关系的模型,用清晰的时间先后顺序和对象间发送的信息来描述了:1.项目主要完成的任务和其时间顺序;2.完成一件事情时各个项目的协作过程;3.对象在时间顺序上的生命周期。

状态图是描述一个类(类本身的数据就是一个封闭状态的集合)的所有状态和状态之间的迁移关系的模型。

1.2 架构设计策略

UML文件本质上是一个Json文件,其内部以Json对象的形式描述对象之间的串联关系,包括父子对象关系、关联关系所连接的两个对象,实现关系所连接的类与接口等等。在做第四单元作业时,不需要我们自己解析UML文件的内容,官方包已经为我们建立了所有UML对象的Java对象,包括UMLClass,UMLInterface,UMLInterfaceRealization等等,并将JSON对象的属性迁移到了Java的类中,用类的形式表述UML对象。我们要实现的UserApi接口的对象在构造时,会被传入一个UMLElement(所有Java的UML对象的父对象,包含所有UML对象的公共属性)数组,我们通过对这个数组的解析来实现若干模型信息的查询。

由于UML对象中表示对象间联系的方法是在某个对象相应的属性处写明所连接的对象的id,并不是java常规的用对象引用的方式构建对象之间的连接,所以在查询对象某些信息时需要查询HashMap或者遍历列表,效率和代码可读性较低。为此,我将某些UML对象封装成一个新的对象,使之内部包含关系对象的引用,方便查询。如把UMLClass对象封装成MyClass对象,内部包含原始的UMLClass对象,此Class继承的父Class(以引用形式给出),此Class的属性、方法数组,此Class直接所实现的接口数组。

这样,可以将类图、顺序图、状态图自底向上地建成一棵树,在查询某个对象的子节点信息时,不需要遍历整个UmlElement数组。树的结构如下所示:

(顺序图、状态图先留个坑)

在实现图的查询操作时,建立三个类: ClassDiagram, InteractionDiagram, StateDiagram,分别用来管理类图、顺序图和状态图的访问,从而可以将MyImplement作为纯粹的对外接口类和通用管理类,具体的任务就转交到对应类型图的管理类来处理即可。每个管理类保存有为该类型图(Diagram)建立的树结构。

特别的,在前两次作业中所建立起的图结构是允许一些不合理的情况发生的,比如类名重名,某些名称为null,只有在查询时才会报错。而在第三次作业中,特别给出了若干判断规则,要求顺序执行检查,如报错,则只要输出报错的那一条然后直接退出即可。这样,我们可以在程序初始化时建好对象树,利用建立好的树结构来判断所给的条件是否满足,无需遍历数列进行查询,这样实现了较高的检查效率。

2. 架构设计思维以及OO方法理解的演进

在学习OO课程之前,相比于Java等面向对象语言,我用的最多的还是C,Python等面向过程的语言(严谨点来说,是使用了面向过程的写法),虽然了解Java的基本语法,但是并不具备很强的面向对象思维,写程序基本上是想到哪里写到哪里,在构建大型程序时很容易出现代码混乱、架构不清的情况。

在学习完OO课程之后,我对面向对象的本质有了更进一步的理解,不再只局限于概念上的理解,更通过写代码做设计有了对这些概念和理论的独到理解。

2.1 第一单元

在第一单元里,我对类、接口等语法概念的理解进一步加深,并理解了这些设计的好处:

类是面向对象设计中一种非常重要的数据和行为抽象方法,每个类有自己独有的数据和方法,并能通过继承的形式来扩充,实现高层抽象的具体化。接口则为类设定了一系列需要实现的方法,只要是实现了这些方法的类的对象,都能以接口类型来引用,从而实现了对一批拥有公共方法的类的抽象和统一。在类中,属性和方法的访问权限可设为私有(private),公共(public),受保护的(protected),来限定外部对类的属性和方法的访问权限,从而实现了类的封装性(即外部只需要知道类能够向外提供的方法和属性即可,无需关注类内部的实现)。这样类的开发者只需保证自己所开发的类不会出现问题即可,无需担心外部的访问方式导致bug,类的使用者保证按规范使用就可不出bug,从而方便了项目的开发迭代,也方便错误的定位和项目的测试。在四次开发过程中我对这些概念和理论的理解更加加深,也深刻体会到了面向对象设计思想对程序开发带来的好处。

2.2 第二单元

在第二单元里,通过电梯调度这个多线程问题,我学会了构造多线程的Java程序,理解了多线程模型下的一些典型的代码构造范例:生产者-消费者模式、流水线模式等。并且学会使用锁机制来避免程序之间的资源访问冲突、规避出现死锁的代码等多线程的基础设计方式。

此外,我明白了面向对象的思想可以使工程设计更加严谨和具有灵活性,比如说要让电梯支持多种调度策略,可以将策略类从电梯类中分离出来,单独实现策略类,在电梯类中实现用于电梯工作的基本方式和策略类的接口,从而实现了电梯策略的可替换。

2.3 第三单元

第三单元我学习了JML语言的书写,以及如何按照JML语言的规格限定来实现Java程序。JML语言是一种非常严谨的形式化的语言,其最大的优点是含义确定,不会存在自然语言表述模糊不清的问题。JML书写的方式是规定函数的前置条件、后置条件、对可变变量的修改、返回值、异常条件等信息,要求所实现的函数满足要求,但并不限定函数的实现方式。JML还非常明确地(近乎数学定义般)指明了测试数据的构造方式和检测方式,只要测试数据满足前置条件的要求,就必须满足后置条件,若不满足,则说明不符合规格。

这给我之后设计程序给予了很好的参考。在设计一些项目的核心部分时(如Linux内核,区块链算法、银行计算等对正确性要求非常严格的场合),可以引入JML规格,在构思好程序的大致结构和实现要求,有必要将对各个函数和类的要求抽象化和严格化为JML语言,依据JML语言完成后续的代码设计。在测试时,根据JML的前置条件构造足够多的测试用例(包括常规数据和所有的边界数据),保证在所有数据下代码一定通过测试,这样就实现了代码的高度正确性。如果条件允许的话,还可使用形式化验证工具证明目标代码的结果空间一定会满足JML的后置条件。不得不说,JML语言实在是工业界严格代码设计的一个有力工具。

2.4 第四单元

与第三单元的JML不同,UML语言是描述java模型架构的工具,它聚焦的角度是项目和工程的顶层设计,往往是在项目未开始写代码之前就要分析和构建的。JML保证了底层具体到每个函数的正确性,而UML则保证顶层类与类之间的关系、处理事件的行为、状态的转移这三方面符合逻辑。在这一单元,我们不止聚焦于会用UML语言,还要明白UML的原理,主要是构建UML元模型相关之间的关系。这样,才能更深的理解UML语言是“Java类模型语言的高层次抽象,是对代码的逻辑化浓缩”的这一关键本质。

3. 测试理解与实践的演进

第一单元

第一单元的测试思路是根据表达式的递归式定义,用Python语言递归式地构造符合格式的表达式,作为数据输入。与数据输入相对的标准输出则采用sympy的展开表达式功能生成,最后用sympy的表达式比较功能与自己生成的表达式展开结果作比较即可。

第二单元

第二单元的测试思路是用Python随机生成乘客序列送入我的程序,然后将程序的输出结果送入自动评测程序进行评测,看其是否满足合法性标准。此次作业对于相同的输入,每个人的程序输出不同,甚至相同的程序不同的运行输出结果也会因为操作系统的CPU运行环境而有所不同,所以对结果的检测主要是通过检测程序是否满足所有正确性规则来实现的。

第三单元

第三单元主要代码的实现都在一个类中,所以对代码正确性的检测可以通过JUnit4来实现。只需要构造符合JML规则的输入,然后判定函数返回值、类中可变变量的前后变化是否满足规则即可。

第四单元

第四单元逻辑比较复杂,难以构造评测机来测试,最方便的方式是找人对拍。

4. 课程收获

  • Java语言的编码能力进一步提升。
  • 学会了多线程的基本编码方式。
  • 系统地学习了一遍正则表达式,并加以应用,对我平时的编程和处理数据有很大的帮助。
  • 具备了系统化地编写自动化测试工具的能力。
  • 面向对象的编程思维得到了进一步的培养。
  • 在各个阶段编程时,我大部分的编码都是基于独立思考,这培养了在大型工程中开始时的整体设计能力,后续逐步按需求迭代的能力。
  • 每个单元都是基于不同领域的编码,在每个编程领域发现bug,调试bug,定位bug,解决和分析bug的过程是一笔不可多得的财富,这将为我未来的编码铺平道路。

5. 课程的改进建议

    1. 在Pre里多加一些Java基础知识的讲解,如HashMap、HashSet等内置数据结构的使用、字符串处理、泛型等。
    1. 建议适当增加一下弱测的强度,感觉有些弱测数据量太少,只有几行,起不到测试的效果。
    1. 在第三单元的设计中引入JML语言格式的检查工具或者其使用方法讲解,要不然现在写JML如同写普通文本一样,不能自动配对括号,判断写法正确与否等,而且现在有些JML语言太长,会让人没有看JML语言的欲望。
posted @ 2022-06-29 15:35  ever_garden  阅读(52)  评论(0编辑  收藏  举报