代码改变世界

OO第三次总结

2018-05-30 19:50  毛钰  阅读(230)  评论(0)    收藏  举报

第三单元学习总结博客

——14061095 毛钰

一、规格化设计

1.发展历史

在应用程序中,Eiffel语言首先提供了《按契约设计》的概念(也就是规格化设计的原型),它关注的是用程序规定软件模块的权利和责任,以确保程序正确性。用文档记载权利和义务的说明,用程序来校验,这就是“规格化设计”的核心。Design by Contract(DbC,契约式设计)是面向对象软件大师Bertrand Meyer对软件构造方法的一个重大贡献,无论是在形式化的数学证明中,还是在实践运用中,都被证明是大幅改善软件工程质量的有效手段。该方法在Eiffel编程语言中获得直接支持,并且可以通过辅助工具在Java语言中运用。

2.重要性

规格化设计是一种设计计算机软件的方法,这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。这种方法又称为“契约式设计”,名字里用到的“规格”或者说“契约”是一种比喻,因为它和商业契约的情况有点类似,因为双双履行义务就可以双双受益。总的来说,规格化设计可以促成以下优点:

1.更优秀的设计

2.更高的可靠性

3.更出色的文档

4.方便调试

5.支持复用

3.核心要素

规格化设计的核心可以用三个关键词来概括:

前置条件(precondition):为了调用函数,必须为真的条件,在其违反时,函数决不调用,传递好数据是调用者的责任。

后置条件(postcondition):函数保证能做到的事情,函数完成时的状态,函数有这一事实表示它会结束,不会无休止的循环。

类不变项(class invariant):从调用者的角度来看,该条件总是为真,在函数的内部处理过程中,不变项可以为变,但在函数结束后,控制返回调用者时,不变项必须为真。

二、根据作业经验总结类和规格的撰写要点

1.理清每个函数的先验条件、函数属性、后验条件并依此加入规格撰写

2.在进入时假定,在退出时保持不变式,并说明副作用

3.在撰写类和方法规格时,最好的办法是先理清程序逻辑框架,撰写规格(和伪代码)来实现框架,然后在写代码来实现最终功能。这样可以免除很多的bug和期望外的问题,并且规格和代码契合度会更高。

三、这几次作业的规格和功能bug

因为这三次作业未出现任何规格互测报错,仅出现了一次功能不完整的互测报错,故不列表,下方为bug描述

第九次作业公测->随机行驶时未选择流量最小边运行

在周围(3x3范围内)没有其他出租车的情况下,一辆空闲状态的出租车采取了掉头操作,重新走了上一步走过的边。(实际上是不应该有掉头操作的,在这种没有其他出租车干扰的情况下),走过的边流量为1,其他边流量为0(如果有其他可联通的边的话)。测试时候的出租车存在着三条联通边(包括上一步走过的边),然而产生了掉头操作。所以我认为有bug。”

该bug是算法细节问题,对寻路算法进行优化后即解决。

四、 前置条件和后置条件不好写法的改进

错误原因

改动前

改动后

条件不准确

/**@ REQUIRES: none
@ MODIFIES: this.taxi
@ EFFECTS: /old(this.taxi) = array(100);
@ */

/**@ REQUIRES: none
@ MODIFIES: this.taxi
@ EFFECTS: /old(this.taxi) = array(100);
@ (\all int i; 0<= i < 100; taxi[i] == 0) 
@ */

前置条件忽视限定条件

/**@ REQUIRES: none
@ MODIFIES: this.taxi
@ EFFECTS: this.taxi[id] = /old(taxi[id]) + grade ==> /result = true
@ */

/**@ REQUIRES: (/all int id, int grade; 0<= id < 80 && grade > 0)
@ MODIFIES: this.taxi
@ EFFECTS: this.taxi[id] = /old(taxi[id]) + grade ==> /result = true
@ */

格式不标准

/** @ REQUIRES: (\all int i,j; 0<= i,j < 80; map[i][j] in {1,2,3}),
(i = 79 && map[i][j] in {2,3}),
(j = 79 && map[i][j] in {1,3})
@ MODIFIES: this.map
@ EFFECTS: this.map.equals(map)
*/

/** @ REQUIRES: (\all int i,j; 0<= i,j < 80; map[i][j] in {1,2,3} &&
(i = 79 && map[i][j] in {2,3}) &&
(j = 79 && map[i][j] in {1,3}))
@ MODIFIES: this.map
@ EFFECTS: this.map.equals(map)
*/

线程具体表述不清晰

/** @ REQUIRES: (\all int root; 0<= root < 6405)

@ MODIFIES: D

@ EFFECTS: (\all int i,j; 0<= i,j < 80; D[(i,j)][(root/80, root%80)] is shortest route value from (i, j) to (root/80, root%80))

@ */

/** @ REQUIRES: (\all int root; 0<= root < 6405)

    @ MODIFIES: D

    @ EFFECTS: (\all int i,j; 0<= i,j < 80; D[(i,j)][(root/80, root%80)] is shortest route value from (i, j) to (root/80, root%80))

    @ THREAD_REQUIRES: none

    @THREAD_EFFECTS: \locked(this.D)

    @ */

后置条件表述不清晰

/** @ REQUIRES: (\all Point x1,x2; 0<= Point.x, Point.y < 80)

@MODIFIES: none

@EFFECTS: this.graph[x1][x2] = 1 == \result = true &&

this.graph[x1][x2] != 1 == \result = flase

@ THREAD_REQUIRES: none

@THREAD_EFFECTS: \locked(this.graph)

*/

/** @ REQUIRES: (\all Point x1,x2; 0<= Point.x, Point.y < 80)

@MODIFIES: none

@EFFECTS: this.graph[x1][x2] = 1 ==> \result = true

this.graph[x1][x2] != 1 --> \result = flase

@ THREAD_REQUIRES: none

@THREAD_EFFECTS: \locked(this.graph)

*/