OO第三次博客作业
• 规格化设计的历史
1950的第一次分离:主程序和子程序的分离
程序结构模型是树状模型,子程序可先于主程序编写。
通过使用库函数来简化编程,实现最初的代码重用。
产生基本的软件开发过程:分析—设计—编码—测试,使大型软件系统的开发成为可能
1975—1980的第二次分离:规格说明(Spec)和体(body)的分离
说明是类型定义和操作描述,体是操作的具体实现。
(具体的例子就是C++,Java等面向对象语言的类说明与类实现的分离)
解决方案设计只关注说明,实现时引用或者设计体。
体的更改、置换不影响规格说明,保证了可移植性。
支持多机系统,但要同样环境。
此时产生了划时代的面向对象技术。
1995—2000的第三次分离:对象使用和对象实现的分离
基于构件开发:
标准化的软件构件如同硬件IC,可插拔,使用者只用外特性,不计内部实现。
Web Services:
软件就是服务。分布式,跨平台,松耦合。
• 规格化设计为什么得到人们的重视?
·对多人开发而言,好的规格设计大大增强代码可读性,便于在程序员之间共享。利于分工协作,从而提高开发效率。
·对长期、非一次性项目而言,规格设计能够减小“遗忘成本”,降低开发人员变动的代价,帮助后来的设计者更好理解函数(方法)作用而忽视具体实现细节,利于后期维护。
• 作业规格bug以及功能bug
|
规格类别 |
Bug产生原因 |
产生行数 |
|
JSF规范 |
Requires采用自然语言叙述,不是布尔表达式 |
12行 |
|
Overview |
漏写 |
13行 |
|
repOK |
漏写 |
15行 |
|
功能bug类别 |
Bug产生原因 |
方法名 |
|
出租车编号输出有误 |
索引没减1 |
LoadFile类的LoadTaxi()方法 |
|
WFS选择流量最少路径 |
漏写 |
Taxi类的RandomRun()方法 |
|
普通出租车走关闭道路 |
普通出租车类的部分未修改 |
Taxi类的MinPathRun()方法 |
• 功能bug与规格bug在方法上的聚集关系
从上面的表格可以看出,这两者并没有多大的关联度,主要还是由于先编码debug再补充规格描述的作业完成顺序。
• 前置条件和后置条件的不好写法及相应改进写法
(1) 前置条件为null的情况
/** * @REQUIRES: request; * @MODIFIES: this; * @EFFECTS: this.req == request; */ =================================================== /** * @REQUIRES: request != null; * @MODIFIES: this; * @EFFECTS: this.req == request; */
(2)前置条件范围约束
/** * @REQUIRES: None; * @MODIFIES: this; * @EFFECTS: this.taxi == Taxilist[num]; */ =================================================== /** * @REQUIRES: 0<=num<100; * @MODIFIES: this; * @EFFECTS: this.taxi == Taxilist[num]; */
(3)后置条件不规范
/** * @REQUIRES: 0<=n<30; * @MODIFIED: this; * @EFFECTS: initialize the Taxi's properties; */ ========================================= /** * @REQUIRES: 0<=n<30; * @MODIFIED: this; * @EFFECTS: this.taxi == Taxilist[n]; */
(4)后置条件不完整
/**
* @REQUIRES: none; * @MODIFIED: this; * @EFFECTS: * (ele.size==0) ==> \result==true; * (\exist int i; 0<=i<els.size; (els[i].num>100 || els[i].num<1) || * (els[i].dir!=1 && els[i].dir!=-1 && els[i].dir!=80 && els[i].dir!=-80) ) || * (els[i].step<0) )) * ==> (\result==false); */
======================================================================================================
/**
* @REQUIRES: none;
* @MODIFIED: this;
* @EFFECTS:
* (ele.size==0) ==> \result==true;
* (\exist int i; 0<=i<els.size; (els[i].num>100 || els[i].num<1) ||
* (els[i].status<0|| els[i].status>3) ) ||
* (els[i].credit<0) ||
* (els[i].dir!=1 && els[i].dir!=-1 && els[i].dir!=80 && els[i].dir!=-80) ) ||
* (els[i].step<0) ))
* ==> (\result==false);
*/
(5)后置条件列举不完善
/** * @REQUIRES: none; * @MODIFIES: this; * @EFFECTS: \result == \old(t)+1000; */ ======================= /** * @REQUIRES: none; * @MODIFIES: this; * @EFFECTS: \result == \old(t)+1000 && this.s==0; */
• 设计规格和撰写规格的基本思路和体会
由于是写先了代码再根据代码来撰写规格的顺序,这几次作业的完成可能已经背离了课程训练目标的初心所在。回过头总结来看,基本思路应该是:根据方法要实现的功能设计相应的规格描述,比如基本的Require、Modified和Effects,这样以来就大致构造出这个方法的框架了,从而在后续的编码过程中,看到规格描述的时候就可以知道这是一个具有什么功能的方法,在调用的时候需要注意什么,调用过程中会有什么参量发生变化,调用之后又会产生什么结果等等。JSF的要求可能实现起来有些繁琐,但是如果使用得当,个人认为可以在一定程度上规范自己的设计流程以及编码行为。
浙公网安备 33010602011771号