2019 - OO第三单元作业总结

一、关于JML

要求:梳理JML语言的理论基础、应用工具链情况

  • JML

    JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言。通过JML及其支持工具,不仅可以基于规格自动构造测试用例,并整合了SMT Solver等工具以静态方式来检查代码实现对规格的满足情况。

    一般而言,JML有两种主要的用法:

    (1)开展规格化设计。这样交给代码实现人员的将不是可能带有内在模糊性的自然语言描述,而是逻辑严格的规格。

    (2)针对已有的代码实现,书写其对应的规格,从而提高代码的可维护性。这在遗留代码的维护方面具有特别重要的意义。

  • 应用工具链

    用OpenJML编译器,编译含有JML的代码,所生成的类文件会在运行时自动检查JML规格,若程序未实现规格中的要求,JML运行期断言检查编译器会抛出一个uncheckedException来说明程序违背了哪一条规格。

    JMLUnitNG可以根据规格的实现自动生成TestNG测试样例。

    JMLdoc工具与Javadoc工具类似,可在生成的HTML格式文档中包含JML规范。

    SMT Solver工具可以以静态方式来检查代码实现对规格的满足情。Openjml使用SMT Solver来对检查程序实现是否满足所设计的规格。

二、关于JMLUnit

要求:部署JMLUnitNG/JMLUnit,针对Graph接口的实现自动生成测试用例, 并结合规格对生成的测试用例和数据进行简要分析

import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MyPathContainerTest {
    private MyPathContainer myPathContainer = new MyPathContainer();
    private MyPath path;

    @BeforeMethod
    public void setUp() {
        path = new MyPath(1,2,3,3,3);
        myPathContainer.addPath(path);
    }

    @AfterMethod
    public void tearDown() {
    }

    @Test
    public void testSize() {
        Assert.assertEquals(myPathContainer.size(), 1);
    }

    @Test
    public void testContainsPath() {
        Assert.assertTrue(myPathContainer.containsPath(path));
    }

    @Test
    public void testGetDistinctNodeCount() {
        Assert.assertEquals(myPathContainer.getDistinctNodeCount(), 3);
    }
}

经过检验,没有问题。

===============================================
Default Suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================

三、架构设计

要求:按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构

  1. 第9次作业

    第9次作业相对简单,只需要实现Path类和PathContainer容器类。在Path中用ArrayList保存一条路径上的节点序,在PathContainer中没加入一条路径就把Path和PathId分别作为Key值存入两个HashMap中,并在查找时使用这两个HashMap进行双向查找。

  2. 第10次作业

    第10次作业在上一次作业的基础上继承,并增加实现了一个Graph类。这一次增加了一个Edge类,存储每个节点连接的节点以及每条边的“权值”。对于isConnectedgetShortestPathLength这两个函数的实现主要基于Dijkstra算法。

  3. 第11次作业

    第11次作业需要实现一个地铁系统,这时只用一个图结构来保存图的信息似乎很难实现。这里相比于上一次作业我增加了另一个图来保存每个节点所连的节点以及对应边所属的线路号,方便后面对换乘的判断。在计算LeastTicketPrice以及LeastUnpleasantValue时要先把两点之间所有的路径算出在从中挑选满足“最小”条件的。但是相比于标程给出的架构,我的架构显然差很多,也因此在强测中产生了CTLE的现象,因此架构和算法方面我还有很大的提升空间。

四、Bug与修复

要求:按照作业分析代码实现的bug和修复情况

  • 第9次作业我出现的Bug主要体现在容器的实现中。这一次作业需要程序具有添加大量Path并快速查找的能力,这时候仅仅使用诸如ArrayList的结构就不合适了,会在很大程度上增加时间复杂度。这个时候使用HashMap双向查找才是高效的形式。
  • 第10次作业我出现的Bug十分可惜,主要是因为对Dijkstra算法的不熟悉而导致少写了一个条件,造成了大面积的WA,这是我今后必须要注意的地方;其次在架构上也没有做出很好的选择,虽然完成了本次的作业,但必定会导致之后作业的正确性大大减小。
  • 第11次作业有不小的难度。首先我的LeastTicketPrice以及LeastUnpleasantValue的计算中出现了问题,忽略了一些关于重复节点的情况,从而导致几个WA;其次由于算法的缺憾,出现了CTLE的情况。在后期修复Bug时,我参照了标程,学习了效率更高的算法,并学习了更加完善清晰的架构,这对于我编程能力的提高具有很大的帮助。

五、心得与体会

要求:阐述对规格撰写和理解上的心得体会

这一单元本身难度不大,代码只需要根据JML给出的规格进行实现即可。在这里JML并不会严格限制函数的实现方法,因此我们需要自己编写合适的方法来实现。在前两次代码中,这个编写方式的难点还没有十分明显,但是在第三次作业中,我们可以发现各式各样的实现方法,而JML只是起到了一个准确描述规格的作用,光是理解了题意其实离实现还很远。

有关于JML的撰写,我认为是一个比较难的过程,因为你需要在编写函数之前就把这个函数的前置条件、后置条件、异常类型等等一系列的情况考虑周全,所以越是复杂的方法,JML的编写越困难。在代码实现之前编写规格一反我以往的上来就写代码的习惯,很难适应,但是对于代码的正确实现以及今后可能的团队协作方面显然是有很重要的意义。

posted @ 2019-05-22 20:44  fqcdwbac  阅读(122)  评论(0编辑  收藏  举报