oo面向对象--规格化设计

规格化设计与抽象

要了解规格化设计首先要了解抽象化的程序设计,两者是密不可分的。

抽象化(Abstraction)

抽象化是将数据与程序,用语义呈现他们的外观,但是隐藏起它的实现细节。

抽象的过程可以看做多对一的映射,让我们忽略个体信息,将不同事物当做相同的事物对待,能够减少程序的复杂度,使得程序员可以专注在处理少数重要的部分。

发展

近几年来,程序员对已经产生的抽象水平产生不满,甚至不满足于在高级语言程序中普遍实现的抽象水平,解决这个问题的方法在于创造“更高级的语言”,用相对固定的数据结构以及有很强功能的原始类型来实现,但是这种方法的缺陷在于嘉定编程语言的设计者在设计语言的时候将大多数用户需要的抽象设计引进设计语言中,包含如此众多的内置抽象的编程语言可能笨拙的很难使用。

另一种可取代的方法是设计一种语言机制,允许程序员在需要的时候构建自己的抽象方法。通常的机制是使用过程(procedure)。编程语言包含了两种重要的抽象方法:参数化抽象(abstraction by parameterization)和规格化抽象(abstraction by specification)。其中:

  • 参数化抽象是用参数替换数据特征来进行抽象。这样能够归纳出模块,从而使其可以用于更多的情况。例如,可以定义一个排序抽象,既能够实现对实数数组的排序,又能够实现对整型数组的排序,或者甚至对数组类型这类一般结构都有用。
  • 规格化抽象是将运行细节(即模块如何实现)抽象为用户所需求的行为(即模块做什么)。这是从具体实现中抽象出模块,需要的仅仅是模块的实现能够匹配我们所依赖的表述形式。

程序设计中,抽象类别包括下列4类:

1:过程抽象:能够引入一些新的操作;

2:数据抽象:能够引入新的数据对象类型;

3:反复运算抽象:能够反复运算遍历在集合中的元素,而不必显示如何获得元素的细节;

4:类型层次:能够从多个单独的数据类型中抽象成几组相关的类型。

规格

抽象用于将一个程序分解为多个模块,然而抽象是无形的,没有描述,我们就无法知道如何将它与其实现的抽象区分。规格描述了服务的提供者和用户之间的协定,提供者同意编写一个属于规格满足集的模块。

规格是对一个方法/类/程序的外部可感知行文的抽象表示,它的目的是为了定义抽象的行为。

如果一个实现提供了所描述的行为,这个实现就满足了一个规格。

规格的含义是满足其所有程序的集合,这个集合称为规格满足集。

作业中的规格bug

此处为自己统计的bug,由于报告的jsf个数有限,自己重新看了一次还是发现了许多bug和不规范的地方。

bug类别 Requires不完整 Modifies不完整 Effects不完整 Requires逻辑错误 Modifies逻辑错误 Effects逻辑错误 Effects内容为实现算法 不符合JSF
个数 7 3 5 0 0 2 0 0
方法行数 3,5,5,13,22,20,4 5,7,7 20,30,15,17,15 30,15

BUG产生原因

1、有些方法或者类的JSF遗漏

比如自己写的Exception类里面忘记写JSF,一些信息存储的类里面的构造方法有时候也会忘记写,还是自己不够细心。

2、没有按照标准格式书写

Effects之后的内容应该为布尔表达式。像是代码中出现的(\result = str),这种里面的=应该写成==

3、程序里面一些传入对象的方法,对应的Requires有的没写。

有传入还是应该写明有Requires的要求,比如传入对象不等于null,或者对象的repOK 为ture之类。

4、某些过程会有附加的隐式输入,例如读入文件和在System.out写信息,这些也属于过程的输入

5、还是偷了很多懒。。

JSF不规范的写法及改进

有些例子前置条件和后置条件一起修改了。

1、前置与后置条件:

    public int getDirection(Coordinate now, Coordinate next){
/**
* @REQUIRES: None;
* @MODIFIES: None;
* @EFFECTS: (next.getX()-now.getX()==1&&next.getY()-now.getY()==0)==>(\result = 0);
(next.getX()-now.getX() == -1 && next.getY()-now.getY()==0)==>(\result = 1);
(next.getX()-now.getX() == 0 && next.getY()-now.getY()==1)==>(\result = 2);
(next.getX()-now.getX()== 0 &&next.getY()-now.getY() == -1)==>(\result = 3);
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
}

这里输入的两个坐标分别是当前坐标和下一步的坐标,这两个坐标需要满足的条件是在地图上是相邻的,由于可能出现道路突然断开的状况,所以两个坐标的连接状态未知,当时想着在代码里面处理了这种异常状况所以没有写requires,但是其实也能在requires中体现,然后在代码中处理这种情况,抛出异常或者返回等操作,如果不写的话也要加入两个坐标不为空,有输入最好要限制其内容,什么都不写不是一种好的习惯。

这里的effects书写也不规范,要用双等号。

修改版本:

public int getDirection(Coordinate now, Coordinate next){
/**
* @REQUIRES: now.getX()>=0 && now.getX() < 80
* && now.getY() >= 0 && now.getY() < 80 && next.getX()>=0
* && next.getX() < 80 && next.getY() >= 0 && next.getY() < 80
* && graph[now.getX()*80+now.getY()][next.getX()*80+next.getY()] == 1;
* @MODIFIES: None;
* @EFFECTS:
* (next.getX()-now.getX()==1&&next.getY()-now.getY()==0)==>(\result = 0);
* (next.getX()-now.getX() == -1 && next.getY()-now.getY()==0)==>(\result == 1);
* (next.getX()-now.getX() == 0 && next.getY()-now.getY()==1)==>(\result == 2);
* (next.getX()-now.getX() == 0 &&next.getY()-now.getY() == -1)==>(\result == 3);
*/
}

2、后置条件:

    public void servingHandler() throws InterruptedException{
/**管理出租车服务状态
* @REQUIRES: None;
* @MODIFIES: this.newtime;this.state;this.coordinate;this.schedulerInfo;
* * this.info;
* @EFFECTS: 对本线程的状态和参数进行改变
* @THREAD_REQUIRES:
* @THREAD_EFFECTS: \locked(trackingInfo);
*/ }

这个方法实现的过程有些复杂,当时直接用自然语言瞎写了一下,没有规范化表述。不过在此函数中调用了其他函数,现在不知道如何将调用其他函数的effects写清楚。。

    public void servingHandler() throws InterruptedException{
/**
* @REQUIRES: None;
* @MODIFIES:\this.newtime;\this.state;
* \this.coordinate;\this.schedulerInfo;\this.info;\System.out;
* InfoQueue;
* @EFFECTS:
* desMove(currentRequest.getDestination());
* this.credit.addAndGet(3);
* InfoQueue.contains(schedulerInfo);
* schedulerInfo.contains(info);
* System.out!=null;
* @THREAD_REQUIRES:None;
* @THREAD_EFFECTS: \locked(trackingInfo);
*/ }

3、前置条件和后置条件:

    @Override
public void desMove(Coordinate destination) throws InterruptedException {
/**出租车找最短路径行驶,找最小流量的边
* @REQUIRES: (\all Coordinate a,b;map;graph[a][b] == 1)
* @MODIFIES: this.coordinate;this.Info;newtime;
* @EFFECTS: this.coordinate == destination;
* @THREAD_REQUIRES:
* @THREAD_EFFECTS:
*/
}

这个函数是移动出租车到目标点,requires没有限制destination的范围,后置条件写的过于简略,没有将移动过程写清楚。

    @Override
public void desMove(Coordinate destination) throws InterruptedException {
/**出租车找最短路径行驶,找最小流量的边
* @REQUIRES: now.getX()>=0 && now.getX() < 80 && now.getY() >= 0
* && now.getY() < 80
* &&(\all Coordinate a,b;a.getX()>=0 && a.getX() < 80 && a.getY() >= 0 && a.getY() < 80 && b.getX()>=0 && b.getX() < 80 && b.getY() >= 0 && b.getY() < 80;graph[a.getX()*80+a.getY()][b.getX()*80+b.getY()] == 1)
* //保证地图连通
* @MODIFIES: this.coordinate;this.Info;newtime;
* @EFFECTS:pathway == TaxiGUI.getInstance().getShortestPath(destination))==>(\all Coordinate a;pathway;this.info.contains(a))
* && (\all int i,int j;j < pathway.size()&&i == j * 5;info.contains(i))
* && \this.coordinate == pathway.get(pathway.size()-1)
* && \this.newtime == newtime + waitime + 5*pathway.size()&&info.contains(newtime);
*/
}

4、前置条件和后置条件:


public static boolean judegeValid(Coordinate a, Coordinate b){
/**
* @REQUIRES: None;
* @MODIFIES: None;
* @EFFECTS: 判断是否符合坐标输入条件
*/ }

由于有输入参数,应该对参数范围加以规范和约束。

effects书写也不符合规范。


public static boolean judegeValid(Coordinate a, Coordinate b){
/**
* @REQUIRES: a instanceof Coordinate && b instanceof Coordinate && a! = null && b!=null;
* @MODIFIES: None;
* @EFFECTS:(a.isOutOfBound()||b.isOutOfBound()||a.equals(b))==> \result == false;
*!(a.isOutOfBound()||b.isOutOfBound()||a.equals(b))==> \result == true;
*/ }

5、前置条件和后置条件:

    public void RoadStatusHandler(String cmd){
/**
* @REQUIRES:
* @MODIFIES: TaxiGUI;
* @EFFECTS: 改变道路开关;
*/
}

String cmd不能是null,虽然也在代码中有处理,effects没写清楚。。

    public void RoadStatusHandler(String cmd){
/**
* @REQUIRES: str instanceof String;str!=null;
* @MODIFIES: TaxiGUI;System.out;
* @EFFECTS: !cmd.isValid()==>System.out == "#set Status Format Error";
* cmd.matches(this.m)&&cmd.isValid()&&m.group(5).equals("OPEN")==>TaxiGUI.getInstance().graph[m.group(1)*80+m.group(2)][m.group(3)*80+m.group(4)]==1;
* cmd.matches(this.m)&&cmd.isValid()&&m.group(5).equals("CLOSE")==>TaxiGUI.getInstance().graph[m.group(1)*80+m.group(2)][m.group(3)*80+m.group(4)]==0;
*/
}

6、前置条件和后置条件

    public void RequestHandler(String cmd) throws RequestFormatErrorException,InterruptedException{
/**
* @REQUIRES:
* @MODIFIES: rcv;
* @EFFECTS: 请求读入
*/
}

没有写异常情况,requires不完整,effects不完整

    public void RequestHandler(String cmd) throws RequestFormatErrorException,InterruptedException{
/**
* @REQUIRES:cmd instanceof String && cmd! = null;
* @MODIFIES: rcv;System.out;
* @EFFECTS: cmd.isValid()==>\this.rcv.contains(new PassengerRequest request);
* !cmd.isValid()==>e == exceptional_behavior(RequestFromatErrorException)&&System.out == e.getMessage(); */
}

功能bug和规格bug在方法上的聚集关系

方法名 功能bug数目 规格bug数目
public void input() 2 1
public void SetRoadStatus(Coordinate a1,Coordiante a2) 1 0
public void randomMove() 1 1

我的功能bug主要在代码实现上面有问题,其实和规格的bug联系并没有很大。

规格设计思路及体会

老师在课上强调,要先写出规格再开始写代码。也就是要先抽象出这个类或者方法的功能,输入输出再进行代码的书写,写出来的内容要符合规格的叙述。所以构思抽象规格是放在首位的,关注的是行为,而不是实现行为的细节。

一个规格的语义包含三部分:需求(Requires),修改(Modifies),结果(Effects)。

1、requires:规格需要有足够的限制性来排除其抽象的用户不可接受的任何实现,这就需要在requires里面明确指出来。一个局部的过程规格总是包含了一个requires格式,有些时候编程应该检查requires中的约束条件,如果不满足就跑出一个异常。

2、modifies:列出了被修改的所有输入名称,做到不遗漏。

3、effects:所有为被requires格式排除的输入描述了过程的行为,必须定义产生了何种输出,同时必须定义被列在modifies格式中的输入做的修改所产生的结果。在本课程中需要用到规范化的表达,实际工程上也有用到简洁的自然语言表达,但是一定要表述清楚,并且符合逻辑。

4、线程类的requires和effects需要书写,但一般不要给使用者限制requires.

实际上因尽可能避免使用requires格式,因为如果输入产生了不满足requires的格式的时候,规格并没有给出相应的操作。所以设计抽象的时候要设计成满足最小限度的受限,对过程行为的细节仅仅做必要的限制,给实现者更多的自由,可以进行更加有效的编程。

oo面向对象--规格化设计的更多相关文章

  1. 规格化设计——OO第三单元总结

    规格化设计--OO第三单元总结 一.JML语言理论基础.应用工具链 1.1 JML语言 ​ JML(java modeling language)是一种描述代码行为的语言,包括前置条件.副作用等等.J ...

  2. 【设计模式系列】之OO面向对象设计七大原则

    1  概述 本章叙述面向向对象设计的七大原则,七大原则分为:单一职责原则.开闭原则.里氏替换原则.依赖倒置原则.接口隔离原则.合成/聚合复用原则.迪米特法则. 2  七大OO面向对象设计 2.1 单一 ...

  3. OO第三单元——JML规格化设计

    OO第三单元--JML规格化设计 JML语言的理论基础以及应用工具链情况 理论基础 JML是对JAVA程序进行规格化设计的一种表示语言,是一种行为接口规格语言.JML整合了Java和JAVAdoc,并 ...

  4. OO_Unit 3 JML规格化设计总结

    OO_Unit 3 JML规格化设计总结 JML语言概述(Level 0) 概念定义   JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言.JML ...

  5. Atitit 基于sql编程语言的oo面向对象大规模应用解决方案attilax总结

    Atitit 基于sql编程语言的oo面向对象大规模应用解决方案attilax总结 1. Sql语言应该得到更大的范围的应用,1 1.1. 在小型系统项目中,很适合存储过程写业务逻辑2 1.2. 大型 ...

  6. Atitit usbQb212 oo 面向对象封装的标准化与规范解决方案java c# php js

    Atitit usbQb212 oo 面向对象封装的标准化与规范解决方案java c# php js 1.1. 封装性是面象对象编程中的三大特性之一  三个基本的特性:封装.继承与多态1 1.2. 魔 ...

  7. java 28 - 1 设计模式 之 面向对象思想设计原则和模版设计模式概述

    在之前的java 23 中,了解过设计模式的单例模式和工厂模式.在这里,介绍下设计模式 面向对象思想设计原则 在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设 ...

  8. OO面向对象第一单元总结

    OO面向对象第一单元总结(表达式求导) 写在前面: 魔鬼课程oo第一单元终于结束,当终究要落笔总结,竟不知从何写起…… 回首再去看第一次的作业,你会满足于那时的幸福,或许,这就是成长吧! 千言万语,一 ...

  9. Java面向对象课程设计——购物车

    Java面向对象课程设计——购物车 小组成员:余景胜.刘格铭.陈国雄.达瓦次仁 一.前期调查 流程 客人(Buyer)先在商城(Mall)中浏览商品(Commidity),将浏览的商品加入购物车(Sh ...

随机推荐

  1. c语言 数组合并

    #include<stdio.h> int main() { int m,n,i,j,k; printf("Enter no. of elements in array1:\n& ...

  2. WCF 客户端调用服务操作的两种方法

    本节的主要内容:1.通过代理类的方式调用服务操作.2.通过通道的方式调用服务操作.3.代码下载 一.通过代理类的方式调用服务操作(两种方式添加代理类) 1.手动编写代理类,如下: 客户端契约: usi ...

  3. VcCallC#_01

    1.C# 代码: using System; using System.Collections.Generic; //using System.Linq; using System.Text; //u ...

  4. AES SBox的构造(python)

    几点需要注意的,求解逆元的时候使用的是拓展欧几里得,但是那些运算规则需要变一变,模2的加减乘除(或者可以理解为多项式的运算) 在进行字节的仿射变换不用进行矩阵的运算. 一个矩阵和一个列向量进行运算的时 ...

  5. 【Mac】小技巧:实现ssh服务器别名免密登录

    前言 我们平常使用ssh user@host然后输入密码的方式来远程链接一个服务器,但是,如果要管理的服务器太多,记住这些服务器的IP和用户名.密码就是一个复杂的工作.当然,我们可以把这些信息用文档记 ...

  6. webpack 多页面支持 & 公共组件单独打包

    webpack - 多页面/入口支持 & 公共组件单独打包 webpack系列目录 webpack 系列 一:模块系统的演进 webpack 系列 二:webpack 介绍&安装 we ...

  7. Unity 中 ContextMenu 的用法

    在自定义脚本中的方法前加入  [ContextMenu("Execute")]  标签,然后将脚本挂载到对象上,可以再编辑模式下执行标记的方法: 自定义脚本如下: using Sy ...

  8. Python的url解析库--urlparse

    一.urlparse解析url的query并构建字典 下面的方法主要的功能: 解析url的各个部分,并能够获取url的query部分,并把query部分构建成dict. 具体的代码实现: >&g ...

  9. arcgis for silverlight 地图放大到某个点或者几何对象

    http://blog.csdn.net/xuan444150/article/details/7727866   分类: silverlight王国 GIS王国 2012-07-09 08:50 1 ...

  10. mysql 随机获取数据并插入到数据库中

    insert into result (user_id, activity_id, number) select user_id, activity_id from `activity_record` ...