面向对象第三次课程总结
一、规格化设计的发展历史
问了百度谷歌,都没什么标准的答案,这里就谈一下自己对于规格意义的理解吧。
在实际工程中,一个完善、统一、严格的规格的确是很有意义的。尤其是在团队协作的项目里,一个统一的规格不仅能提高代码的可读性,同时,也方便使用者使用别人的编写的方法,在使用时只用关心其作用,而不必去考虑其具体实现
二、bug分析
规格bug
整体规范: this 应写为 \this
功能性bug
出现走“回头路”、“不存在的路”的现象
原因:线程安全问题,当出租车进程执行pointbfs寻找最短(考虑流量)路径的同时,若流量刷新了,可能导致出租车无法找到流量最小的最短路径,可能会走一条固定的路径。
出现出租车停止的问题
原因:当存在较多请求同时执行时,由于对出租车运行时sleep(500)的方法进行过修正,计算执行时间,直接调用sleep方法,当计算结果为负数时,程序抛出异常,该出租车进程直接结束了……
规格bug和功能性bug间的联系
可以说对于道路流量的线程安全的考虑,都未在规格中体现出来,也就忽略了在执行pointbfs时可能会刷新流量,就导致了bug 的产生。
而对于进程直接结束的问题,也可以说是对sleep方法的前置条件的忽略导致的bug。
三、规格不好的写法
未列举出应有的前置条件
private static boolean isCrossroads(int index) // @REQUIRES: ; { int count = 0; for(int i=0;i<4;i++) { int next = index + Constant.moveOffect[i]; if(next<0||next>6399) { continue; } if(guigv.m.graph[index][next]==1) count++; } if(count<=2) return false; return true; }
应改为
private static boolean isCrossroads(int index) // @REQUIRES: 0 <= index < 6400;
前置条件不全
private boolean canPickUp(Point _point, Point reqPoint) // @REQUIRES: _point != null && reqPoint != null; // @MODIFIES: ; // @EFFECTS: (req.canPickUp == true) ==> \result == true; else ==> \result == false; { if ((_point.x - reqPoint.x) > 2 || (reqPoint.x - _point.x) > 2) { return false; } if ((_point.y - reqPoint.y) > 2 || (reqPoint.y - _point.y) > 2) { return false; } return true; }
应改为
private boolean canPickUp(Point _point, Point reqPoint) // @REQUIRES: _point != null && reqPoint != null && 0<= _point.x <80 && 0<= _point.y <80 && 0<= _ reqPoint.x <80 && 0<= _ reqPoint.y <80 ;
后置条件有误
private boolean canPickUp(Point _point, Point reqPoint) // @REQUIRES: _point != null && reqPoint != null; // @MODIFIES: ; // @EFFECTS: (req.canPickUp == true) ==> \result == true; else ==> \result == false; { if ((_point.x - reqPoint.x) > 2 || (reqPoint.x - _point.x) > 2) { return false; } if ((_point.y - reqPoint.y) > 2 || (reqPoint.y - _point.y) > 2) { return false; } return true; }
应改为
private boolean canPickUp(Point _point, Point reqPoint) // @EFFECTS: (\result == true) ==> (_point.x – 2 <= reqPoint.x <= _point.x + 2 && _point.y – 2 <= reqPoint.y <= _point.y + 2);
后置条件不必使用自然语言的地方使用了自然语言
public int getStatus() // @EFFECTS: 获取出租车状态; { synchronized (this.statusLock) { return this.status; } }
应改为
public int getStatus()
// @EFFECTS: \result == \this.status;
后置条件使用自然语言
private static void taxiInit() // @REQUIRES: ; // @MODIFIES:taxi.state; // @EFFECTS: Initialization of uninitialized taxi in file; { int x1, y1; for (int i = 0; i < Constant.taxiNum; i++) { if (Constant.taxi[i] == null) { x1 = (int) (Math.random() * 400) % 80; y1 = (int) (Math.random() * 400) % 80; if(i >= Constant.normalTaxi) Constant.taxi[i] = new Taxi(i, x1, y1); else Constant.taxi[i] = new TaxiVip(i, x1, y1); } } }
应改为
private static void taxiInit() /** @EFFECTS: (\all int i; 0<=i<30; taxi[i] == new TaxiVip()); * (\all int i; 0<=i<30; taxi[i] == new Taxi()); */
前置条件后置条件都有问题
public boolean equals(RequestData b) /** * @REQUIRES: None; * @MODIFIES: None; * @EFFECTS: (this == b)==> \result == true; (this != b) ==> \result == false; */ { if (!this.pointFrom.equals(b.pointFrom))
return false;
if (!this.pointTo.equals(b.pointTo)) return false; if (!((this.reqTime / (100L)) == (b.reqTime / (100L)))) return false; return true; }
应改为
public boolean equals(RequestData b) /** * @REQUIRES: b != null; * @MODIFIES: None; * @EFFECTS: (\result == true) ==> (\this.pointFrom == b.pointFrom && \this.pointTo == b.pointTo && \this.reqTime/ (100L) == b.reqTime/ (100L)); *(\result != true) ==> (\this.pointFrom != b.pointFrom || \this.pointTo != b.pointTo || \this.reqTime/ (100L) != b.reqTime/ (100L)); */
四、心得体会
这几次作业主要是对程序设计和规格的考察,但我还是在实现功能之后,再根据自己的程序来书写相应的规格。这几次作业,我都是在周三才基本实现功能,也就只剩下一点时间来写JSF了,所以程序中多见使用自然语言之处,也存在较多的漏写某些条件的情况。
可以说,在我这几次的作业中,规格设计未起到积极作用,仅仅是为了少扣分而去写的。在这样的过程中,规格的作用根本没有体现出来。而在实际工程中,应当是先完善规格设计,再据此实现各个方法。