OO游记之五月篇

一、规格化设计

  让我们从程序设计的演变分析来看下规格设计

  1950年代,第一次分离,主程序和子程序的分离

  程序结构模型是树状模型,子程序可先于主程序编写。通过使用库函数来简化编程,实现最初的代码重用。产生基本的软件开发过程:分析—设计—编码—测试,使大型软件系统的开发成为可能

  1975—1980年代,第二次分离,规格说明和体的分离

  说明是类型定义和操作描述,体是操作的具体实现。(具体的例子就是C++,Java等面向对象语言的类说明与类实现的分离。)解决方案设计只关注说明,实现时引用或者设计体。体的更改、置换不影响规格说明,保证了可移植性。支持多机系统,但要同样环境。此时产生了划时代的面向对象技术。

  1995—2000年代,第三次分离,对象使用和对象实现的分离

  基于构件开发:标准化的软件构件如同硬件IC,可插拔,使用者只用外特性,不计内部实现。

  Web Services:软件就是服务。分布式,跨平台,松耦合。

  从个人的角度来看,规格化的设计是很有必要的,按照标准的JSF去写代码,可以保证代码的质量,提高代码的复用性。在团队工作中,代码不只是给自己看的,为了让自己代码的使用方法很快被别人了解,代码规格就十分重要了。

二、规格BUG分析

第九次作业

第十次作业

编号 规格BUG类别 所在方法 方法代码行数
1 针对构造方法,初始状态repOK为真 Request.repOK() 12
2 Modifies不完整 Taxi() 10
3 Requires逻辑错误 RequestQueue.size() 1
4 Requires逻辑错误 TaxiGroup.statusInquire() 1

1.我写了两个不同参数的Requeset的构造器,其中一个构造器并未对PrintStream属性进行初始化,导致repOK检查时返回false

2.Taxi构造器方法对出租车的所有属性进行了初始化设置,但我在Modifies中少写了几个属性

3.(这个属于手残的错误)粘贴上个方法的Requires下来的时候忘了修改了

4.此方法传入的参数的为出租车的编号,理应在0~99的范围内,否则可能发生数组越界错误,我忽视了这一点,没有在Requires中声明

第十一次作业

编号 规格BUG类别  所在方法  方法代码行数
JSF不符合规范  TaxiGroup.run()  29
JSF不符合规范   Scheduler.run() 100 
JSF不符合规范   InputHandler.run() 75 
Modifies不完整   Request.set_add() 73 
Modifies不完整   LightMap.run() 20 
Requires不完整  lightBlockJudge() 15 
Requires不完整   RequestQueue.remove()
Modifies不完整  Map.mapInit() 54 
Modifies逻辑错误  Map.pointbfs() 42 

1.我在run方法中进行了线程控制,synchronized了两个对象,而没有书写多线程控制规格

2.依然是上个原因,进行synchronized控制而没有书写多线程控制规格

3.依然是上个原因,进行synchronized控制而没有书写多线程控制规格

4.在方法中对HashSet进行了修改,但没有在Modifies中声明

5.在方法中对lightMap进行了修改,但没有在Modifies中声明

6.本次作业中新添加了此方法,忘了写规格(很是尴尬)

7.方法为从队列中移除下标为传入参数的元素,但在Requires中只写了index<queue.size,没有对负数进行限制,应为0<=index<queue.size,避免产生越界错误

8.在方法中对distance进行了修改,但没有在Modifies中声明

9.在方法中只是对局部变量view进行了修改,不应写在Modifies声明中

规格BUG产生的原因

  首先,当然是自己的问题,对于大量的方法补充JSF,各种粗心大意导致被扣分,除了下标为负没有考虑到,其他的均是很低级的错误;其次,第一次写规格是在第九次作业,而这次作业是承袭第七次作业,因此大家都是后来对很多方法补充规格,这样就违反了本应有的顺序;最后,对于规格化的书写教学部分感觉不是很详细,后来下发的JSF样例包含的情况有限,导致大家对规格的理解不是那么深刻,写出很多不标准的规格。

三、前置条件和后置条件改进

前置条件

1.未限制数据范围

1    /**
2      * @REQUIRES: None;
3      * @MODIFIES: None;
4      * @EFFECTS: \result == (taxi_group[id].status_get());
5      */
6     public Status statusInquire(int id) {
7         return taxi_group[id].status_get();
8     }    

 改进方法

1    /**
2      * @REQUIRES: 0<=id<=99;
3      * @MODIFIES: None;
4      * @EFFECTS: \result == (taxi_group[id].status_get());
5      */
6     public Status statusInquire(int id) {
7         return taxi_group[id].status_get();
8     }        

2.构造方法未进行限制

1   /**
2      * @REQUIRES: None;
3      * @MODIFIES: this.rq;
4      * @EFFECTS: this.rq == rq;
5      */
6     public InputHandler(RequestQueue rq) {
7         this.rq = rq;
8     }

改进方法

1   /**
2      * @REQUIRES: rq != null;
3      * @MODIFIES: this.rq;
4      * @EFFECTS: this.rq == rq;
5      */
6     public InputHandler(RequestQueue rq) {
7         this.rq = rq;
8     }

3.未进行类型判断

 1     /**
 2      * @REQUIRES: r != null;
 3      * @MODIFIES: None;
 4      * @EFFECTS: (r.src in map && r.dst in map) ==> \result true;
 5      *              !(r.src in map && r.dst in map) ==> \result false;
 6      */
 7     public boolean formatCheck(Request r) {
 8         if(r.srcxGet()>=80 || r.srcyGet()>=80) return false;
 9         if(r.dstxGet()>=80 || r.dstyGet()>=80) return false;
10         if(r.dstGet()==r.srcGet()) return false;
11         return true;
12     }

改进方法

 1     /**
 2      * @REQUIRES: r != null && r instanceof Request;
 3      * @MODIFIES: None;
 4      * @EFFECTS: (r.src in map && r.dst in map) ==> \result true;
 5      *              !(r.src in map && r.dst in map) ==> \result false;
 6      */
 7     public boolean formatCheck(Request r) {
 8         if(r.srcxGet()>=80 || r.srcyGet()>=80) return false;
 9         if(r.dstxGet()>=80 || r.dstyGet()>=80) return false;
10         if(r.dstGet()==r.srcGet()) return false;
11         return true;
12     }

4.类型描述不完整

 1     /**
 2      * @REQUIRES: rq != null && rq instance of RequestQueue && taxi_group != null && taxi_group instanceof Taxi[];
 3      * @MODIFIES: rq,this.tg;
 4      * @EFFECTS: this.rq == rq;
 5      *           this.tg == taxi_group;
 6      */
 7     public Scheduler(RequestQueue rq, Taxi[] taxi_group) {
 8         this.rq = rq;
 9         this.tg = taxi_group;
10     }

改进方法

 1     /**
 2      * @REQUIRES: rq != null && rq instance of RequestQueue && taxi_group != null && \all int i; 0<=i<=taxi_group.length; taxi_group[i] instanceof Taxi;
 3      * @MODIFIES: rq,this.tg;
 4      * @EFFECTS: this.rq == rq;
 5      *           this.tg == taxi_group;
 6      */
 7     public Scheduler(RequestQueue rq, Taxi[] taxi_group) {
 8         this.rq = rq;
 9         this.tg = taxi_group;
10     }

5.未进行范围限制

 1     /**
 2      * @REQUIRES: None;
 3      * @MODIFIES: None;
 4      * @EFFECTS: \result == (flowmap.get(Key(x1,y1,x2,y2))==null ? 0 :flowmap.get(Key(x1,y1,x2,y2)));
 5      * @THREAD_REQUIRES: \locked(this);
 6      * @THREAD_EFFECTS: \locked();
 7      */
 8     public static int GetFlow(int x1,int y1,int x2,int y2){
 9         synchronized (flowmap) {
10             return flowmap.get(Key(x1,y1,x2,y2))==null ? 0 :flowmap.get(Key(x1,y1,x2,y2));
11         }
12     }

改进方法

 1     /**
 2      * @REQUIRES: 0<=x1<=79 && 0<=y1<=79 && 0<=x2<=79 && 0<=y2<=79;
 3      * @MODIFIES: None;
 4      * @EFFECTS: \result == (flowmap.get(Key(x1,y1,x2,y2))==null ? 0 :flowmap.get(Key(x1,y1,x2,y2)));
 5      * @THREAD_REQUIRES: \locked(this);
 6      * @THREAD_EFFECTS: \locked();
 7      */
 8     public static int GetFlow(int x1,int y1,int x2,int y2){//查询流量信息
 9         synchronized (flowmap) {
10             return flowmap.get(Key(x1,y1,x2,y2))==null ? 0 :flowmap.get(Key(x1,y1,x2,y2));
11         }
12     }

后置条件

1.尽量避免使用自然语言

1   /**
2      * @REQUIRES: None;
3      * @MODIFIES: gap, lightTime;
4      * @EFFECTS: true ==> (Initialize the LightMap's information);
5      */
6     public LightMap() {
7         gap = 500 + new Random().nextInt(501);
8         lightTime = gap;
9     }

改进方法

 1   /**
 2      * @REQUIRES: None;
 3      * @MODIFIES: gap, lightTime;
 4      * @EFFECTS: gap = 500 + new Random().nextInt(501);
 5                 lightTime = gap;
 6      */
 7     public LightMap() {
 8         gap = 500 + new Random().nextInt(501);
 9         lightTime = gap;
10     }

2.缺少多线程规格

1     /**
2      * @EFFECTS: \result == queue.size;
3      */
4     public synchronized int size() {
5         return this.queue.size();
6     }

改进方法

1     /**
2      * @EFFECTS: \result == queue.size;
3      * @THREAD_REQUIRES: \locked(this);
4      * @THREAD_EFFECTS: \locked();
5      */
6     public synchronized int size() {
7         return this.queue.size();
8     }

3.不符合布尔表达式规范

 1     /**
 2      * @REQUIRES: None;
 3      * @MODIFIES: rq,this.tg;
 4      * @EFFECTS: this.rq = rq;
 5      *           this.tg = taxi_group;
 6      */
 7     public Scheduler(RequestQueue rq, Taxi[] taxi_group) {
 8         this.rq = rq;
 9         this.tg = taxi_group;
10     }

改进方法

 1     /**
 2      * @REQUIRES: None;
 3      * @MODIFIES: rq,this.tg;
 4      * @EFFECTS: this.rq == rq;
 5      *           this.tg == taxi_group;
 6      */
 7     public Scheduler(RequestQueue rq, Taxi[] taxi_group) {
 8         this.rq = rq;
 9         this.tg = taxi_group;
10     }

4.尽量避免使用自然语言

 1     /**
 2      * @REQUIRES: None;
 3      * @MODIFIES: this.id,this.pos,this.posx,this.posy,this.pre,this.status,this.waittime,this.taxiTime,this.blockFlag;
 4      * @EFFECTS: true ==> (Initialize taxi);
 5      */
 6     public Taxi(int id) {
 7         this.id = id;
 8         Random rand = new Random();
 9         this.pos = rand.nextInt(6400);
10         pre = pos;
11         xy_set();
12         this.status = Status.WAITING;
13         this.waittime = 0;
14         taxiTime = 500;
15         blockFlag = false;
16         Main.taxigui.SetTaxiStatus(id, new Point(posx,posy), 2);
17     }

改进方法

 1 /**
 2      * @REQUIRES: None;
 3      * @MODIFIES: this.id,this.pos,this.posx,this.posy,this.pre,this.status,this.waittime,this.taxiTime,this.blockFlag;
 4      * @EFFECTS: this.id == id;
 5         rand == new Random();
 6         this.pos == rand.nextInt(6400);
 7         pre == pos;
 8         this.status == Status.WAITING;
 9         this.waittime == 0;
10         taxiTime == 500;
11         blockFlag == false;
12      */
13     public Taxi(int id) {
14         this.id = id;
15         Random rand = new Random();
16         this.pos = rand.nextInt(6400);
17         pre = pos;
18         xy_set();
19         this.status = Status.WAITING;
20         this.waittime = 0;
21         taxiTime = 500;
22         blockFlag = false;
23         Main.taxigui.SetTaxiStatus(id, new Point(posx,posy), 2);
24     }

5.忽略函数中调用了其他函数

1     /**
2      * @REQUIRES: map.contains(pos);
3      * @MODIFIES: this.posx,this.posy;
4      * @EFFECTS: this.pos == pos;
5      */
6     public void pos_set(int pos) {
7         this.pos = pos;
8         xy_set();
9     }

改进方法

 1     /**
 2      * @REQUIRES: map.contains(pos);
 3      * @MODIFIES: this.posx,this.posy;
 4      * @EFFECTS: this.pos == pos;
 5      *              posy == pos%80;
 6      *              posx == (pos-posy)/80;
 7      */
 8     public void pos_set(int pos) {
 9         this.pos = pos;
10         xy_set();
11     }

四、聚集关系分析

  方法名  错误原因 功能BUG数  规格BUG数
作业9 Taxi.work() 忘了使用addFlow()增加流量 1 0
作业10 Taxi.work() 在STOP状态对流量处理不当 1 0
TaxiGroup.run() 上一个问题的连带问题 1 0
作业11 LightMap.lightMapInit() 没有过滤空格和制表符 1 0

  通过结果来看似乎功能bug和规格bug并没有什么关系,因为其实是先完成了作业的功能要求才添加的规格,而规格的bug是由于在写规格过程中对函数没有细致分析造成的。所以本质上来说还是由于对规格的理解不当造成的.

五、设计规格和撰写规格的基本思路和体会

  很惭愧,我的代码规格都是写好函数之后才补上去的,所以谈不上设计,只能写一点撰写的方法了。

  对于Requires部分,要对函数传入的参数,函数中用到的一些全局变量进行严格约束,从类型到范围都要考虑全面。Modifies部分要对函数中修改的变量列出来,不重不漏。Effects部分就比较麻烦了,要使用布尔表达式对result的情况进行撰写,需要对函数的作用进行良好的抽象化表达,尽量避免使用自然语言,才能写出一份良好的规格。

六、碎碎念

  这三次作业其实写的并不是很累,基本都是到周二才开始动手写,从结果来看,功能上的bug有自己实现方法有问题的,也有手残的,然而JSF被扣的分基本上都是因为手残,得承认自己有不足,但是这门课面向运气的测试依然让人很不爽。得承认JSF对于工程化有重要作用,不过在这么课中,JSF用来被扣分还是有待商榷的~

猜你喜欢

转载自www.cnblogs.com/blackpineapple/p/9108149.html