OO第三阶段纪实


$0 写在前面


万里长征已过大半,即将迎来胜利的曙光。一路走来,经历过种种艰难,体会颇深。希望能记录下这篇博文,来总结这一个月来的收获与感悟。


$1 规格化设计的发展历史


上世纪50年代,软件伴随着第一台电子计算机的问世诞生了。以写软件为职业的人也开始出现,他们多是经过训练的数学家和电子工程师。1960年代美国大学里开始出现授予计算机专业的学位,教人们写软件。在计算机系统发展的初期,由于目的的单一性,软件的通用性是很有限的。大多数软件是由使用该软件的个人或机构研制的,软件往往带有强烈的个人色彩。早期的软件开发也没有什么系统的方法可以遵循,软件设计是在某个人的头脑中完成的一个隐藏的过程。而且,除了源代码往往没有软件说明书等文档。

从60年代中期到70年代中期是计算机系统发展的第二个时期,在这一时期软件开始作为一种产品被广泛使用,出现了“软件作坊”专职应别人的需求写软件。这一软件开发的方法基本上仍然沿用早期的个体化软件开发方式,但软件的数量急剧膨胀,软件需求日趋复杂,维护的难度越来越大,开发成本令人吃惊地高,而失败的软件开发项目却屡见不鲜。“软件危机”就这样开始了!“软件危机”使得人们开始对软件及其特性进行更深一步的研究,人们改变了早期对软件的不正确看法。早期那些被认为是优秀的程序常常很难被别人看懂,通篇充满了程序技巧。现在人们普遍认为优秀的程序除了功能正确,性能优良之外,还应该容易看懂、容易使用、容易修改和扩充。

软件工程是一门研究如何用系统化、规范化、数量化等工程原则和方法去进行软件的开发和维护的学科。通过不断努力,人们逐渐解决了软件危机,并认识到规格化设计的重要性,在此期间,一些重要的文档格式的标准被确定下来,包括变量、符号的命名规则以及源代码的规范式。后来随着发展,这些规范逐渐形成了软件开发中的规格化设计,并且由于其高效性与高可靠性,越来越受到软件开发人员的重视。

那么规格化设计的出现,为工程人员带来了哪些方面的便利呢?

伴随着计算机行业的迅速发展,为了解决程序可靠性等问题,结构化、模块化的设计为程序员提供了使用接口。每个模块各司其职,这样的程序便于扩展和维护,大大降低了当时开发者的困难。同时由于面向对象语言兴起,结构化、模块化的思想在面向对象语言里作用被体现得更加彻底。与此同时,为了提高程序语言的规范性,对类和方法进行更好的维护,对其进行规范化设计,也使得数据变得更加安全可控,测试也更加简单易行。

为了类和方法能够变得规范可控,对类和方法进行规范化要求就变得有必要起来。在工程里面, 一个程序也许会有多人同时进行编写,那么由于每个人不同的代码习惯,可能产生不同的设计理念,通过规格化设计也可以同步多人的设计方法,避免产生设计上的漏洞。规格化的程序不仅更易于调试,也更容易被维护,有利于程序的长远生存和发展。这些都是规格化设计的优势所在。


$2 规格bug统计


【表一】被报告的bug概览

   功能bug  规格bug  是否相关
OO9  1  1  不相关
OO10  2  2  不相关
OO11  2  1  不相关

【注】从表中可以看出功能bug产生的原因与规格无关,故不构成聚集关系。

【表二】被报告bug详细信息

 Bug类别  Bug内容  出现位置 

 代码行数

功能bug  未派单给信用最高车辆  Dispatcher  23
规格bug  未编写jsf  Taxi.get_stateName()  15
其他  说明书不够详细  ReadMe  0
规格bug  repOK方法不能直接返回(*2)  repOK()  1
规格bug  jsf为表述成javadoc格式  everywhere  ∞
功能bug  关闭道路无法打开  gui.initmatrix()  53

【注】由于在第11次作业中遇到了好朋友测试我的作业,该同学前若干次作业被报告了较多bug,出于人道主义援助,我允许该同学申报3个与代码本身无关的bug。即,我并不认为是由于本人代码错误而导致的bug,故在表二中未进行呈现。


$3 规格bug的避免


根据几次作业被报告的规格bug,总结一下避免此类bug的方法:

首先,要认真对待jsf的书写。jsf对我们编写方法起到了规范和约束的重要作用,因此必须对其给出足够的重视,一个端正的态度是写好JSF的第一步。

其次,要仔细复习课件和课本中的内容。通过对样例的研读,将在极大程度上提高我们所编写规格的正确性。

最后,要增加复查环节,当依照相应的jsf编写完方法代码后,需要带入规格进行验证,以保证其正确性。


$4  JSF的修改


 

以下列举若干在我的JSF存在的问题以及相应的修改策略:

$4-1 Pre-condition 不正确 

【No.1】

问题代码段:

public void setMessage(String m) {
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:message;
         *        @EFFECTS:message != \old(message);
         */
        message = m;
    }

问题:这段代码未对传入参数进行约束,改进如下:

public void setMessage(String m) {
        /**        
         *         @REQUIRES:String m != null;
         *        @MODIFIES:message;
         *        @EFFECTS:message != \old(message);
         */
        message = m;
    }

【No.2】

问题代码段:

protected void waitLight(int n) {
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:time;
         *        @EFFECTS:(check if taxi has to wait for traffic light) == true;
         */
        while(true) {
            try {
                sleep(1);
            } catch (InterruptedException e) {
                System.out.println("Exception while waiting for lights");
                System.exit(0);
            }
            if(n == 0) {                           // require for NS
                if(light.getGreenDir() == Dir.NS) {
                    break;
                }
            }
            else if(n == 1) {
                if(light.getGreenDir() == Dir.EW) {
                    break;
                }
            }
        }
    }

改进后:

protected void waitLight(int n) {
        /**        
         *         @REQUIRES:\all int n : (n == 0 || n == 1);
         *        @MODIFIES:time;
         *        @EFFECTS:(check if taxi has to wait for traffic light) == true;
         */
        while(true) {
            try {
                sleep(1);
            } catch (InterruptedException e) {
                System.out.println("Exception while waiting for lights");
                System.exit(0);
            }
            if(n == 0) {                           // require for NS
                if(light.getGreenDir() == Dir.NS) {
                    break;
                }
            }
            else if(n == 1) {
                if(light.getGreenDir() == Dir.EW) {
                    break;
                }
            }
        }
    }

【No.3】

问题代码段:

protected void checkLight(int n) {
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:time;
         *        @EFFECTS:(check if taxi has to wait for traffic light) == true;
         */
        if(n == 0) {                          // going up
            if(heading == HeadDir.N || heading == HeadDir.E) {
                if(light.getGreenDir() == Dir.EW) {
                    waitLight(0);
                }
            }
        }
        else if(n == 1) {                    // going down
            if(heading == HeadDir.S || heading == HeadDir.W) {
                if(light.getGreenDir() == Dir.EW) {
                    waitLight(0);
                }
            }
        }
        else if(n == 2) {                    // going left
            if(heading == HeadDir.N || heading == HeadDir.W) {
                if(light.getGreenDir() == Dir.NS) {
                    waitLight(1);
                }
            }
        }
        else if(n == 3) {                    // going right
            if(heading == HeadDir.S || heading == HeadDir.E) {
                if(light.getGreenDir() == Dir.NS) {
                    waitLight(1);
                }
            }
        }
    }

修改后:

protected void checkLight(int n) {
        /**        
         *         @REQUIRES:\all int n : 0 <= n <= 3;
         *        @MODIFIES:time;
         *        @EFFECTS:(check if taxi has to wait for traffic light) == true;
         */
        if(n == 0) {                          // going up
            if(heading == HeadDir.N || heading == HeadDir.E) {
                if(light.getGreenDir() == Dir.EW) {
                    waitLight(0);
                }
            }
        }
        else if(n == 1) {                    // going down
            if(heading == HeadDir.S || heading == HeadDir.W) {
                if(light.getGreenDir() == Dir.EW) {
                    waitLight(0);
                }
            }
        }
        else if(n == 2) {                    // going left
            if(heading == HeadDir.N || heading == HeadDir.W) {
                if(light.getGreenDir() == Dir.NS) {
                    waitLight(1);
                }
            }
        }
        else if(n == 3) {                    // going right
            if(heading == HeadDir.S || heading == HeadDir.E) {
                if(light.getGreenDir() == Dir.NS) {
                    waitLight(1);
                }
            }
        }
    }

【No.4】

问题代码段:

protected boolean bound(int from_x,int from_y,int to_x,int to_y) {
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:None;
         *        @EFFECTS:\all (int to_x,to_y ==> (0<=to_x<80)) && 
         *                   (has path between from and to) ==> \result == true;
         */
        if(to_x >= 0 && to_y >= 0 && to_x < 80 && to_y < 80 && graph[from_x * 80 + from_y][to_x * 80 + to_y] == 1) {
            return true;
        }
        else {
            return false;
        }
    }

修改后:

protected boolean bound(int from_x,int from_y,int to_x,int to_y) {
        /**        
         *         @REQUIRES:int from_x,from_y,to_x,to_y;0<=from_x,from_y,to_x,to_y<=80;
         *        @MODIFIES:None;
         *        @EFFECTS:\all (int to_x,to_y ==> (0<=to_x<80)) && 
         *                   (has path between from and to) ==> \result == true;
         */
        if(to_x >= 0 && to_y >= 0 && to_x < 80 && to_y < 80 && graph[from_x * 80 + from_y][to_x * 80 + to_y] == 1) {
            return true;
        }
        else {
            return false;
        }
    }

【No.5】

问题代码段:

public Light(TaxiGUI g) {
        /**
         * @REQUIRES:true;
         * @MODIFIES:gui;
         * @EFFECTS:this != \old (this);
         */
        
        gui = g;
    }

修改后:

public Light(TaxiGUI g) {
        /**
         * @REQUIRES:g != null;
         * @MODIFIES:gui;
         * @EFFECTS:this != \old (this);
         */
        
        gui = g;
    }

$4-2 Post-condition 不正确

【No.1】

问题代码段:

private static int getDegrees(int i ,int j) {
        /**
         * @REQUIRES:true;
         * @MODIFIES:none;
         * @EFFECTS:\result = (degrees of this point);
         */
        int cnt = 0;
        if((i >= 0 && i <= 79 && j >= 0 && j < 79) && guigv.m.graph[i * 80 + j][i * 80 + j + 1] == 1) {
            cnt ++;
        }
        if((i >= 0 && i <= 79 && j > 0 && j <= 79) && guigv.m.graph[i * 80 + j][i * 80 + j - 1] == 1) {
            cnt ++;
        }
        if((i >= 0 && i < 79 && j >= 0 && j <= 79) && guigv.m.graph[i * 80 + j][(i + 1) * 80 + j] == 1) {
            cnt ++;
        }
        if((i > 0 && i <= 79 && j >= 0 && j <= 79) && guigv.m.graph[i * 80 + j][(i - 1) * 80 + j] == 1) {
            cnt ++;
        }
        return cnt;
    }

@EFFECTS必须是一个boolean型的表达式,故需要使用==来代替=

改进后:

private static int getDegrees(int i ,int j) {
        /**
         * @REQUIRES:true;
         * @MODIFIES:none;
         * @EFFECTS:\result == (degrees of this point);
         */
        int cnt = 0;
        if((i >= 0 && i <= 79 && j >= 0 && j < 79) && guigv.m.graph[i * 80 + j][i * 80 + j + 1] == 1) {
            cnt ++;
        }
        if((i >= 0 && i <= 79 && j > 0 && j <= 79) && guigv.m.graph[i * 80 + j][i * 80 + j - 1] == 1) {
            cnt ++;
        }
        if((i >= 0 && i < 79 && j >= 0 && j <= 79) && guigv.m.graph[i * 80 + j][(i + 1) * 80 + j] == 1) {
            cnt ++;
        }
        if((i > 0 && i <= 79 && j >= 0 && j <= 79) && guigv.m.graph[i * 80 + j][(i - 1) * 80 + j] == 1) {
            cnt ++;
        }
        return cnt;
    }

【No.2】

问题代码段:

private void timePass() {
        /**
         * @REQUIRES:true;
         * @MODIFIES:time;
         * @EFFECTS:time != \old(time);
         */
        try {
            sleep(cycle);
        } catch (InterruptedException e) {
            System.out.println("Exception in light thread!");
            System.exit(0);
        }
    }

@EFFECTS约束不够具体需要给出较强的约束

改进后:

private void timePass() {
        /**
         * @REQUIRES:true;
         * @MODIFIES:time;
         * @EFFECTS:time != \old(time) + cycle;
         */
        try {
            sleep(cycle);
        } catch (InterruptedException e) {
            System.out.println("Exception in light thread!");
            System.exit(0);
        }
    }

【No.3】

问题代码段:

private void initialize() {
        /**
         * @REQUIRES:true;
         * @MODIFIES:cycle,green,lightMap,gui;
         * @EFFECTS:(Initialize the lights in the map) == true;
         */
        cycle = (int) ((Math.random() * 500) + 500);
        int r = (int) (Math.random());
        if(r >= 0.5) {
            green = Dir.NS;
            for(int i = 0 ; i < 80 ; i ++) {
                for(int j = 0 ; j < 80 ; j ++) {            
                    if(lightMap[i][j] == 1) {
                        gui.SetLightStatus(new Point(i,j), 2);
                    }                
                }
            }            
        }
        else {
            green = Dir.EW;
            for(int i = 0 ; i < 80 ; i ++) {
                for(int j = 0 ; j < 80 ; j ++) {
                    if(lightMap[i][j] == 1) {
                        gui.SetLightStatus(new Point(i,j), 1);
                    }
                }
            }
        }
    }

尽量减少自然语言的使用

改进后:

private void initialize() {
        /**
         * @REQUIRES:true;
         * @MODIFIES:cycle,green,lightMap,gui;
         * @EFFECTS:lightMap != \old(lightMap);
         */
        cycle = (int) ((Math.random() * 500) + 500);
        int r = (int) (Math.random());
        if(r >= 0.5) {
            green = Dir.NS;
            for(int i = 0 ; i < 80 ; i ++) {
                for(int j = 0 ; j < 80 ; j ++) {            
                    if(lightMap[i][j] == 1) {
                        gui.SetLightStatus(new Point(i,j), 2);
                    }                
                }
            }            
        }
        else {
            green = Dir.EW;
            for(int i = 0 ; i < 80 ; i ++) {
                for(int j = 0 ; j < 80 ; j ++) {
                    if(lightMap[i][j] == 1) {
                        gui.SetLightStatus(new Point(i,j), 1);
                    }
                }
            }
        }
    }

【No.4】

问题代码段:

protected void initialize() {
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:graph,gui;
         *        @EFFECTS:graph and gui has been initialized;
         */
        graph = gui.get_graph();
        gui.SetTaxiStatus(taxiNum, new Point(curLocation.getX(),curLocation.getY()) , 2);
    }

需要减少自然语言的使用

改进后:

protected void initialize() {
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:graph,gui;
         *        @EFFECTS:this.gui !=\old(this.gui);
         */
        graph = gui.get_graph();
        gui.SetTaxiStatus(taxiNum, new Point(curLocation.getX(),curLocation.getY()) , 2);
    }

【No.5】

问题代码段:

protected void serve(){
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:normal taxi state;
         *        @EFFECTS:run on taxis service;
         */
        src = new Coordinate(req.getSrc_x(),req.getSrc_y());
        dst = new Coordinate(req.getDst_x(),req.getDst_y());
        gui.SetTaxiStatus(taxiNum, new Point(curLocation.getX(),curLocation.getY()) , 3);
        boolean fetch = true;    // from current spot to src spot 
        boolean arrived = false;
        while(!arrived) {
            stay(500);
            if(fetch) {
                fetch = toSrc();
            }
            else {
                arrived = toDst();
            }
        }
    }

应减少自然语言的使用。

改进后:

protected void serve(){
        /**        
         *         @REQUIRES:true;
         *        @MODIFIES:normal taxi state;
         *        @EFFECTS:for normal taxis: taxi.state != \old(taxi.state);
         */
        src = new Coordinate(req.getSrc_x(),req.getSrc_y());
        dst = new Coordinate(req.getDst_x(),req.getDst_y());
        gui.SetTaxiStatus(taxiNum, new Point(curLocation.getX(),curLocation.getY()) , 3);
        boolean fetch = true;    // from current spot to src spot 
        boolean arrived = false;
        while(!arrived) {
            stay(500);
            if(fetch) {
                fetch = toSrc();
            }
            else {
                arrived = toDst();
            }
        }
    }

$5 写在最后


又一阶段的OO任务告一段落,在最后,为这段时间的努力做一个简单的总结,也记录一下几次作业的所见所感。

对于这门课程,无论是从前人抑或是同学那里所得到的反馈来看,负面评论较多。平心而论,在这门课程中,我确实学习到了一些面向对象编程的基本技巧,当然要有更深一步的了解,还有赖于以后更多的训练。吴际等老师为了这门课可以说花费了很多心思,尽管确实会有同学为了获取分数,而利用机制的漏洞,但我仍然认为掌握我们所必须学会的技能才是这门课程的核心所在。同时,吴际老师的严格要求也让我彻底放弃了对分数的追求。上一次的上机实验课的时候我未能按时出席,因为室友胸部意外受伤,我陪同前往医院检查。事出突发,未能及时向学院递交请假申请,但吴际老师拒绝接受任何补交假条。于是现在关于这门课程最后我能否通过,仍然是个未知数。虽然吴际老师对我们的要求过于严苛,但我也仍然十分感激,哪怕每次训练只有一点点收获,日积月累,我相信便会有所突破。

看淡分数,提升能力,享受编码。

猜你喜欢

转载自www.cnblogs.com/chrischen98/p/9103010.html