OO第三次单元总结

 一、规格化设计发展历史 

  软件规格化方法,最早可追溯到20世纪50年代后期对于程序设计语言编译技术的研究,当时出现了各种语法分析程序自动生成器以及语法制导的编译方法,使编译系统的开发从“手工艺制作方式”发展成具有牢固理论基础的系统方法。规格化设计的研究高潮始于20世纪60年代后期,针对当时所谓的“软件危机”,人们提出种种解决方法,如采用工程方法来组织、管理开发过程和通过钻研规律建立严密的理论以指导开发实践。

  经过30多年的研究和应用,如今人们在规格化设计取得了大量、重要的成果,从早期最简单的一阶谓词演算到现在应用于不同领域、不同阶段的基于逻辑、状态机、网络、进程、代数等众多规格形式化方法,它的发展趋势是逐渐融入设计开发的各个阶段,从需求分析、功能描述、算法设计、编程、测试直到维护。

  规格化设计对代码的创作者和使用者都有重要的作用。对于编程者,规范的设计有助于架构的建立和调整,有助于完善修正细节,有助于未来的维护和扩展;对于使用者,规格化的呈现有助于理解剖析,避免不必要的误解和分歧,同时也利于高效的阅读和学习。

 

 二、bug分析 

  

  三次作业总共被报了四个规格bug,很遗憾的是其中有三个都是“忘记写了”……emm反思一下第十次可能和赶时间有关,但是第十一次在时间蛮充裕的情况下就真的是粗心没检查的锅。另外一个关于repOK的bug,我觉得测试者说的很有道理。因为在原来的repOK方法中,只要出现了对象型的变量我一律用“!=null”来处理,但是想想每个对象的类中也有它自己的repOK,理应传承下来,只有满足了所有的repOK才能说明科学合理性。

  

  虽然从表格上看,功能bug与规格bug确实没有重合的地方,但是这并不意味着两者就毫无关联。两次作业中功能出现的问题集中在input、run、randomdrive这些代码规模较大,逻辑较复杂的方法中,本身规格就很难概括,只能借助自然语言的帮助,加上关键步骤的布尔表达式来描述。由于规格无法涵盖细小逻辑,很难体现出错误疏漏,或者换一种说法,书写规格没有起到应有的作用,所以从报告bug的角度,就看不出联系了。

 

 三、规格改进示例 

  • 前置条件  
/**
     * @REQUIRES:
     *         0<=index<=6399;
     * @MODIFIES:None;
     * @EFFECTS:
     *         normal_behavior:
     *            !(\exist int next;map.reachlist[index].contains(next)) ==> \result==index;
     *             在index的可达节点中随机选取一个两点之间边流量最小的节点next.
     *             \result==next;
     *         exception_behavior(Exception e): 
     *             \result==index;
  */

                               

/**
     * @REQUIRES:
     *         0<=index<=6399;
     *         0<=oldindex<=6399;
     * @MODIFIES:None;
     * @EFFECTS:
     *         normal_behavior:
     *            !(\exist int next;map.reachlist[index].contains(next)) ==> \result==index;
     *             在index的可达节点中随机选取一个两点之间边流量最小的节点next.
     *             \result==next;
     *         exception_behavior(Exception e): 
     *             \result==index;
  */

······································································································································

/**
     * @REQUIRES:
     *         0<=start<=6399;
     *         0<=end<=6399;
     *         0<=flow<=100;
     * @MODIFIES:
     *         \this.flow;
     * @EFFECTS:
     *         \this.flow[start][end]==flow;
     *         \this.flow[end][start]==flow;
  */

                               ↓

/**
     * @REQUIRES:
     *         0<=start<=6399;
     *         0<=end<=6399;
     *         distance from start to end is 1.
     *         0<=flow<=100;
     * @MODIFIES:
     *         \this.flow;
     * @EFFECTS:
     *         \this.flow[start][end]==flow;
     *         \this.flow[end][start]==flow;
  */

······································································································································

/**
     * @REQUIRES:
     *         0<=index<=6399;
     *         0<=next<\this.reachlist[index].size();
     * @MODIFIES:None;
     * @EFFECTS:
     *         type==0 ==> \result==\this.reachlist[index].get(next);
     *         type==1 ==> \result==\this.initreachlist[index].get(next);
  */

                               ↓

/**
     * @REQUIRES:
     *         0<=index<=6399;
     *         0<=next<\this.reachlist[index].size();
     *         type==0 || type==1;
     * @MODIFIES:None;
     * @EFFECTS:
     *         type==0 ==> \result==\this.reachlist[index].get(next);
     *         type==1 ==> \result==\this.initreachlist[index].get(next);
  */

······································································································································

/**
     * @REQUIRES:None;
     * @MODIFIES:None;
     * @EFFECTS:
     *         (r's time,start_x,start_y,end_x,end_y are equal to this's) ==> \result==true;
     *         !(r's time,start_x,start_y,end_x,end_y are equal to this's) ==> \result==false;
  */

                               ↓

/**
     * @REQUIRES:
     *         r!=null;
     * @MODIFIES:None;
     * @EFFECTS:
     *         (r's time,start_x,start_y,end_x,end_y are equal to this's) ==> \result==true;
     *         !(r's time,start_x,start_y,end_x,end_y are equal to this's) ==> \result==false;
  */

······································································································································

/**
     * @REQUIRES:None;
     * @MODIFIES:None;
     * @EFFECTS:
     *         \result==\this.inputs.get(i).start_x;
  */

                               ↓

/**
     * @REQUIRES:
     *         0<=i<\this.inputs.size();
     * @MODIFIES:None;
     * @EFFECTS:
     *         \result==\this.inputs.get(i).start_x;
  */

······································································································································

  • 后置条件  
/**
     * @REQUIRES:None;
     * @MODIFIES:
     *         \this.credit;
     * @EFFECTS:
     *         \this.credit==\this.credit+1;
  */

                               ↓

/**
     * @REQUIRES:None;
     * @MODIFIES:
     *         \this.credit;
     * @EFFECTS:
     *         \this.credit==\old(\this.credit)+1;
     */

······································································································································

/**
     * @REQUIRES:
     *         req!=null;
     * @MODIFIES:None;
     * @EFFECTS:
     *         \result == request in inputs that equals req ;
     */

                               ↓

/**
     * @REQUIRES:
     *         req!=null;
     * @MODIFIES:None;
     * @EFFECTS:
     *         \result == (\exist Request r; inputs.contains(r);r.equals(req));
     * @THREAD_REQUIRES:
     *         \locked(\this);
     * @THREAD_EFFECTS:
     *         \locked();
     */

······································································································································

/**
     * @REQUIRES:
     *         req!=null;
     * @MODIFIES:
     *         \this.inputs;
     * @EFFECTS:
     *         \this.inputs.contains(req) ;
     * @THREAD_REQUIRES:
     *         \locked(\this);
     * @THREAD_EFFECTS:
     *         \locked();
     */

                               ↓

/**
     * @REQUIRES:
     *         req!=null;
     * @MODIFIES:
     *         \this.inputs;
     * @EFFECTS:
     *         \this.inputs.contains(req) && \this.inputs.size()=\old(\this.inputs).size()+1;
     * @THREAD_REQUIRES:
     *         \locked(\this);
     * @THREAD_EFFECTS:
     *         \locked();
     */

······································································································································

/**
     * @REQUIRES:None;
     * @MODIFIES:
     *         \this.reachlist;
     *         \this.initreachlist;
     * @EFFECTS:
     *         \this.reachlist == new Vector<Integer>();
     *         (\all Vector x;reachlist.contains(x);x!=null);
     *         \this.initreachlist == new Vector<Integer>();
     *         (\all Vector x;initreachlist.contains(x);x!=null);
     */

                               ↓

/**
     * @REQUIRES:None;
     * @MODIFIES:
     *         \this.reachlist;
     *         \this.initreachlist;
     * @EFFECTS:
     *         \this.reachlist!=null;
     *         (\all Vector x;reachlist.contains(x);x!=null);
     *         \this.initreachlist!=null;
     *         (\all Vector x;initreachlist.contains(x);x!=null);
     */

······································································································································

/**
     * @REQUIRES:None;
     * @MODIFIES:None;
     * @EFFECTS:
     *         \result==queue!=null && inputs!=null && taxigui!=null && outFile!=null && taxis!=null && taxiInfo!=null && map!=null;
     */

                               ↓

/**
     * @REQUIRES:None;
     * @MODIFIES:None;
     * @EFFECTS:
     *         \result==queue!=null &&  inputs!=null && taxigui!=null && outFile!=null && taxis!=null && taxiInfo!=null && map!=null && queue.repOK() && inputs.repOK() && (\all Taxi t;taxis.contains(t);t.repOK()) && map.repOK();
     */

······································································································································

 

 四、思路与体会 

  由于出租车的框架是在第七次作业时搭建好的,后面基本没有做出大的变动,所以大部分的规格是看着方法补充。前置条件就从传入的参数入手,基本类型需要判断在指定范围内,对象类型则要求不为空。中间条件抓住本类的类变量,逐一检查是否在此方法中被改变。后置条件比较复杂,需要兼顾条件判断、数组遍历、返回值、类变量前后改变等,如果是逻辑太多的方法就只能挑出关键步骤,借助自然语言描述。

  不同的遭遇,不同的体会。在三次作业的互测过程中,测试者并没有死抠我的规格细节,扣的分主要是因为自己的粗心大意,所以在承受范围之内。至于书写规格的体会,由于没有做到像老师在课堂上说的 “先写规格后写代码”,整个过程可以说是“重温方法思路,再按规定格式翻译一遍”。虽然体验效果有些欠佳,但依然不能否认规格化设计的重要性。在真正的工程化编程中,规格的确有提高效率,减少出错的作用。同时我也认为,“规格化”不仅仅是贯彻体现在方法前的几行JSF注释中,更重要的是从构想到实施的过程,真正具有 “规格化”的思想。

posted @ 2018-05-29 12:49  joyceu  阅读(151)  评论(0编辑  收藏  举报