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任务告一段落,在最后,为这段时间的努力做一个简单的总结,也记录一下几次作业的所见所感。
对于这门课程,无论是从前人抑或是同学那里所得到的反馈来看,负面评论较多。平心而论,在这门课程中,我确实学习到了一些面向对象编程的基本技巧,当然要有更深一步的了解,还有赖于以后更多的训练。吴际等老师为了这门课可以说花费了很多心思,尽管确实会有同学为了获取分数,而利用机制的漏洞,但我仍然认为掌握我们所必须学会的技能才是这门课程的核心所在。同时,吴际老师的严格要求也让我彻底放弃了对分数的追求。上一次的上机实验课的时候我未能按时出席,因为室友胸部意外受伤,我陪同前往医院检查。事出突发,未能及时向学院递交请假申请,但吴际老师拒绝接受任何补交假条。于是现在关于这门课程最后我能否通过,仍然是个未知数。虽然吴际老师对我们的要求过于严苛,但我也仍然十分感激,哪怕每次训练只有一点点收获,日积月累,我相信便会有所突破。
看淡分数,提升能力,享受编码。
OO第三阶段纪实的更多相关文章
- OO第三阶段作业总结
调研: 最早的程序设计是直接采用机器语言来编写的,或者使用二进制码来表示机器能够识别和执行的指令和数据.机器语言的优点在于速度快,缺点在于写起来实在是太困难了,编程效率低,可读性差,并且 ...
- OO第三阶段总结
软件形式化方法历史 形式化方法的研究高潮始于20世纪60年代后期,针对当时所谓"软件危机",人们提出种种解决方法,归纳起来有两类:一是采用工程方法来组织.管理软件的开发过程:二是深 ...
- 2021S软件工程——结对项目第三阶段
2021S软件工程--结对项目第三阶段 2021春季软件工程(罗杰 任健) 项目地址 1020 1169 1 实践反思 1.1 问题分析 两人习惯不一致 没有具体制定时间节点 写完代码才开始" ...
- OO前三次作业思考(第一次OO——Blog)
OO前三次作业总结 基于度量分析程序结构 由于三次作业较多,决定分析内容.功能最为复杂的第三次作业. 上图为第三次作业的类图.我使用了一个抽象类Factor,写了五个因子继承Factor,然后又单独开 ...
- Bete冲刺第三阶段
Bete冲刺第三阶段 今日工作: web: 检索了各类资料,今日暂时顺利解决了hibernate懒加载异常的问题,采用的凡是也比较简单就是添加了一个OpenSessionInViewFilter的过滤 ...
- [课程设计]Scrum 3.1 多鱼点餐系统开发进度(第三阶段项目构思与任务规划)
Scrum 3.1 多鱼点餐系统开发进度(第三阶段项目构思与任务规划) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题:餐厅到 ...
- Scrum 3.1 多鱼点餐系统开发进度(第三阶段项目构思与任务规划)
Scrum 3.1 多鱼点餐系统开发进度(第三阶段项目构思与任务规划) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题:餐厅到 ...
- 分布式事务 & 两阶段提交 & 三阶段提交
可以参考这篇文章: http://blog.csdn.net/whycold/article/details/47702133 两阶段提交保证了分布式事务的原子性,这些子事务要么都做,要么都不做. 而 ...
- 第一阶段,第二阶段,第三阶段团队github更新项目地址
第一阶段:https://github.com/yuhancheng/stage-1--last-sprint 第二阶段:https://github.com/yuhancheng/stage-2-- ...
随机推荐
- Yii2几个要注意的小地方
本人新手, 刚接触Yii, 记录下遇到的坑, 大神请绕道/ 1. //插入数据到数据库, 需要 new 一下,设置属性: $info = new BasicInfo(); $info -> se ...
- Laravel 的十八个最佳实践
本文翻译改编自 Laravel 的十八个最佳实践 这篇文章并不是什么由 Laravel 改编的 SOLID 原则.模式等. 只是为了让你注意你在现实生活的 Laravel 项目中最常忽略的内容. ...
- 小程序和H5互调
小程序跳H5页面 https://blog.csdn.net/mytljp/article/details/81030687(copy) H5页面跳小程序 https://blog.csdn.net/ ...
- 动态SQL2
set标签 存放修改方法,我们之前写的更新方法是全字段的更新,或者是指定字段的更新,现在我想实现一个新功能,传入的Employee包含什么字段,数据库就更新相对应的列值: 如果我们啥也不做直接上< ...
- Django Rest framework 框架
一.开发模式: 1. 普通开发方式(前后端放在一起写) 2. 前后端分离(前后台通过ajaxo交互) 后端(django rest framework写的) <----ajaxo---> ...
- 结巴(jieba)分词
一.介绍: jieba: “结巴”中文分词:做最好的 Python 中文分词组件 “Jieba” (Chinese for “to stutter”) Chinese text segmentatio ...
- netstat -na 查看有大量TIME_WAIT解决办法(修改内核参数)
# netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c 16 CLOSING 130 ESTABLISHED 298 FIN_WA ...
- python数据结构与算法第七天【链表】
1.链表的定义 如图: 注意: (1)线性表包括顺序表和链表 (2)顺序表是将元素顺序地存放在一块连续的存储区里 (3)链表是将元素存放在通过链构造的存储快中 2. 单向链表的实现 #!/usr/bi ...
- 学习 Spring (九) 注解之 @Required, @Autowired, @Qualifier
Spring入门篇 学习笔记 @Required @Required 注解适用于 bean 属性的 setter 方法 这个注解仅仅表示,受影响的 bean 属性必须在配置时被填充,通过在 bean ...
- 线程同步Volatile与Synchronized(一)
volatile 一.volatile修饰的变量具有内存可见性 volatile是变量修饰符,其修饰的变量具有内存可见性. 可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改 ...