OO第三次总结

Posted ll--

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OO第三次总结相关的知识,希望对你有一定的参考价值。

OO第三次总结

规格化设计的发展历史和受到重视的原因

? 20世纪60年代,软件出现严重的危机,Dijkstra于1968年发表著名的《GOTO有害论》,由此引发了软件界长达数年的论战,并产生了结构化的程序设计方法。随着计算机技术的发展,结构设计化语言和结构化分析已经无法满足用户的需求,OOP由此应运而生,即面向对象的程序设计。面向对象程序设计的诞生是程序设计方法学的一场革命,大大提高了开发效率,减少了软件开发的复杂度,提高了软件的可维护性,可扩展性。1990年以来,面向对象分析、测试、度量和管理研究都得到长足的发展。规格化设计随其而生,为了提高程序的规范性,对类。方法等进行规范化设计,有利于模块化的划分。最实际的,通过规格化设计,在进行大型多人的开发工作时,可以确保程序员之间能够便捷地在他人的基础之上开始自己的工作,大大提高了工作效率,也方便他人理解代码,所以受到了大家的重视。

规格bug分析

Bug类型 出现位置 方法行数
Effects不完整 mapInfo类point2N函数 5
Modifies逻辑错误 Taxi类refreshGUI函数 11

产生规格bug的原因

protected  void refreshGUI() {
    /**
     *  @REQUIRES: None;
     *  @MODIFIES: None;
     *  @EFFECTS: None;
     *  @THREAD_EFFECTS: \locked(readWriteLock.readLock);
     */
    readWriteLock.readLock().lock();
    int tempStatus = 0;
    //其中0- 停止运行;1-服务(在运行且车内有乘客);2-等待服务(在运行但车内无乘客),3-准备服务。
    switch (status) {
        case STOPING: tempStatus = 0; break;
        case SERVING: tempStatus = 1; break;
        case WAITING: tempStatus = 2; break;
        case ORDERED: tempStatus = 3; break;
    }
    readWriteLock.readLock().unlock();
    gui.SetTaxiStatus(No, currentPos, tempStatus);
}

在这个函数中我忽略了调用gui方法时会更改gui,更改如下:

/**
 *  @REQUIRES: None;
 *  @MODIFIES: gui;
 *  @EFFECTS: gui.SetTaxiStatus(No,currentPos,tempStatus);
 *  @THREAD_EFFECTS: \locked(readWriteLock.readLock);
*/  
private int point2N(Point point) {
    /**
         *  @REQUIRES: point != null;
         *  @MODIFIES: None;
        *   @EFFECTS: \result == point.x * mapSize + point.y;
        */
    if (point == null) {
        System.out.println("ERROR : NULL POINTER!");
        return 0;
    }
    return point.x * mapSize + point.y;
}

这里返回值忽略了point=null时为0的情况,更改如下:

  /**
    *  @REQUIRES: point != null;
    *   @MODIFIES: None;
    *   @EFFECTS:   \result == point.x * mapSize + point.y && point != null
    *           || \result == 0 && point == null;
    */

改进规格

1.mapInfo 类的 refreshMap 函数

    public void refreshMap(int[][] map, TaxiGUI gui) {
        /**
         *  @REQUIRES: map!=null;
         *  @MODIFIES: this.map;gui;
        *   @EFFECTS: this.map == map;
        */
        readWriteLock.writeLock().lock();
        this.map = map;
        if (this == instance) {
            gui.LoadMap(map, mapSize);
        }
        readWriteLock.writeLock().unlock();
    }

在这个方法中要载入一张新的地图,这时需要对地图大小进行判断,否则如果map仅仅非空,大小不正确可能导致后续程序崩溃。更改如下:

/**
    * @REQUIRES: map!=null && map.length == MAPSIZE 
    *                    && (\all Integer i; i<MAPSIZE && i>=0; map[i].length == MAPSIZE);
    * @MODIFIES: this.map;gui;
    * @EFFECTS: this.map == map;
    */

2.MapFlow 类的 setMapFlow 方法

public void setMapFlow(ArrayList<Point> p1s, ArrayList<Point> p2s, ArrayList<Long> values) {
        /**
         *  @REQUIRES: p1s!=null;p2s!=null;values!=null;
         *  @MODIFIES: edgeFlows;
        *   @EFFECTS: None;
        */
    readWriteLock.writeLock().lock();
    for (int i = 0; i < MapSize*MapSize*2; i++) {
        edgeFlows[i] = new EdgeFlow();
    }
    for (int i = 0; i < p1s.size(); i++) {
        int n = Point2N(p1s.get(i), p2s.get(i));
        if (map.isConnected(p1s.get(i), p2s.get(i))) {
            edgeFlows[n].flow = values.get(i);
        }
    }
    readWriteLock.writeLock().unlock();
}

在这个方法的 JSF 中仅要求了三个列表参数非空,但是在函数实现时没有判断列表长度为零或三个列表不等长的情况。更改如下:

/**
 *  @REQUIRES: p1s!=null && p2s!=null && values!=null 
 *          && p1s.size() > 0 
 *          && p2s.size() == p1s.size() && values.size() == p1s.size();
 *  @MODIFIES: edgeFlows;
 *  @EFFECTS: None;
*/

3.RequestMatrix 类的 isSame 方法

public synchronized boolean isSame(ReqSchedular req) {
        /**
         *  @REQUIRES: request!=null;
         *  @MODIFIES: None;
        *   @EFFECTS: requestSchedular.equals(request);
        */
    for (ReqSchedular reqSchedular : reqMatrix[req.Src().x][req.Src().y].reqList) 
    {
        if (reqSchedular.equals(req)) {
            return true;
        }
    }
    return false;
}

这里是首次写规格时不熟悉遗留下的错误,缺少锁的影响且返回值格式不正确,更改如下:

    /**
     *  @REQUIRES: request!=null;
     *  @MODIFIES: None;
    *   @EFFECTS: \result == true ==> 
    *           ( \exist ReqSchedular reqS; 
    *             reqMatrix[req.Src().x][req.Src().y].reqList.contains(reqS);
    *             reqS.equal(req) )
    *   @THREAD_EFFECTS: \locked(this);
    */

4.MapFlow 类的 updateEdgeFlow方法

public void updateEdgeFlow(Point p1, Point p2, long value) {
    /**
     *  @REQUIRES: p1!=null;p2!=null;value!=null;
     *  @MODIFIES: edgeFlows[n];
    *   @EFFECTS: None;
    */
    if (p1.equals(p2))
        return;
    int n = Point2N(p1, p2);
    if (map.isConnected(p1, p2)) {
        readWriteLock.readLock().lock();
        edgeFlows[n].readWriteLock.writeLock().lock();
        edgeFlows[n].flow = edgeFlows[n].flow + value;
        edgeFlows[n].readWriteLock.writeLock().unlock();
        readWriteLock.readLock().unlock();
    }
}

更改为:

/**
 *  @REQUIRES: p1!=null;p2!=null;value!=null;
 *  @MODIFIES: edgeFlows[n];
*   @EFFECTS: n = Point2N(p1, p2) && edgeFlows[n].flow == \old(edgeFlows[n].flow) + value;
*   @THREAD_EFFECTS: \lock(readWriteLock.readLock);
*                   \lock(edgeFlows[n].readWriteLock.writeLock)
*/

5.FlowThread 类 run方法

    public void run() {
        /**
         *  @REQUIRES: p1 != null && p2 != null;
         *  @MODIFIES: None;
        *   @EFFECTS:None;
        */
        try {
        if (p1.equals(p2))
            return;
        try {
            sleep(FlowTimeWindow);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            //e.printStackTrace();
            System.out.println("Flow Thread : sleep crash! ");
        }
        mapFlow.updateEdgeFlow(p1, p2, -1);
        } catch (Exception e) {
            System.out.println("Flow Thread Exception!");
        }
    }

改为:

/**
 *  @REQUIRES: p1 != null && p2 != null;
 *  @MODIFIES: None;
 *  @EFFECTS: !p1.equals(p2) ==> (sleep(FolwTimeWindow) && mapFlow.updateEdgeFlow(p1,p2,-1));
*/

分析被报的功能bug与规格bug在方法上的聚集关系

? 在互测中被挑出的功能bug和规格bug关联并不大,可能是笔者刚刚接触JSF,有许多函数方法功能可以正确实现但是功能并不完善,所以被找了规格bug,笔者认为互测阶段被报的大量 JSF 的bug往往是测试者刻意为之(当然我也承认书写不够规范)。功能bug往往是比较复杂的函数中存在逻辑漏洞,这类函数的规格比较复杂,可能存在逻辑错误,但测试者并没有仔细分析,所以大多没有报JSF bug。我想这也是这种测试机制存在的一些问题,被测出的规格问题并不能反映程序的功能实现问题,而对于复杂函数,被测者通过写规格为做出的优化,也很少通过测试反映出来。

设计规格和撰写规格的基本思路和体会

? 写规格可以强制要求程序员降低简化每个成员方法的复杂度,在写程序之前能够明确一个方法的具体作用和影响,对程序作者和读者而言都是一个明确、严谨的说明。但有的时候一些逻辑不好表述的过程的确很难写出简洁的规格,甚至让规格比代码还长。在一些开源代码中,许多规格都是一些自然语言的注释,反而更让人清晰的理解一个方法的作用。在我个人看来,用布尔表达式书写的规格在有些情况下是比较冗余,且难懂的,虽然从逻辑上可能会更准确。另外对于OO课程的 JSF 测试部分,我认为并没有达到很好的效果,许多人的恶意挑错反而降低了同学们的学习积极性。

以上是关于OO第三次总结的主要内容,如果未能解决你的问题,请参考以下文章

OO第三次阶段总结

OO课程第三次总结QWQ

oo第三次总结

OO第三次总结

oo第三次总结

OO第三次课程总结分析