类规格设计

由于没能找到关于类规格设计的发展历史,所以结合程序设计思想的发展来谈谈规格化设计。

最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的指令和数 据。简单来说,就是直接编写 0 和 1 的序列来代表程序语言。机器语言由机器直接执行,速度快,但一个很明显的缺点就是:写起来实在是太困难了;于是有了面向过程变成,相比面向机器的思想来说,面向过程是一次思想上的飞跃,将程序员从复杂的机器操作和运行的细节中解放出来,转而关注具体需要解决的问题;面向过程的语言也不再需要和具体的机器绑定,从而具备了移植 性和通用性;面向过程的语言本身也更加容易编写和维护。这些因素叠加起来,大大减轻了程序员的负担, 提升了程序员的工作效率,从而促进了软件行业的快速发展。

但在这种设计模式下,不可避免的会产生面条式的代码,极大地限制了程序的规模——结构化设计应运而生:它是一种编程范型,采用子程序(函数就是一种子程序)、代码区块、for循环以及while循环等结构,来替换传统的goto。希望借此来改善计算机程序的明晰性、质量以及开发时间,并且避免写出面条式代码,这就是规格化设计的起源,并且一直发展至今。

在实际的生活中,开发都是以团队为单位的,团队之间的交流主要是通过代码,所以代码要具有可读性;同时,实际的生活中代码的维护也是相当重要的,而维护代码的那些人却并不一定是代码的作者,这就更要求代码要具有很好的可维护性;另外,在我们开发程序的过程中,规格的设计更有助于避免浪费更多的时间来debug,如果一开始设计好了规格,然后严格按照这个规格来完成代码,可以很好的避免功能性bug。因此,由于以上列举出来的部分优点,这些看似优点浪费时间的类规格一直在人们心中占据重要的位置。

bug分析

本次课程如果烧脑的地方除了互测估计就是这个jsf的书写了,并不是说难度很大,而是要写得真正的规范感觉太难,而且很耗时间,写了这么多规格并没有很大的收获。所以这几次的规格都是写完了方法然后后面来添加的,并没有达到规格应有的左右,比如实验课上先写规格然后再写方法代码。这几次作业测我程序的同学都很nice,并没有扣我规格的bug。

关于功能性的bug,由于这几次作业是在第七次作业的基础上进行修改,所以只要实现了指导书的要求,应该能很好的避免功能性bug。第十一次作业被同学报了一个功能bug,是关于走回头路的。我自己本地跑了一下他的测试代码(所有的车初始化在一个点,而且该点周围只有一条边),现象是根本看不出现象,可能是因为电脑太卡了吧也可能是程序本身就有问题,不过我依然觉得这种测试样例可能大部分代码跑出来效果都一样,所以自己也没去管这个bug了。

不好的写法和改进

(1)以下是我出租车类中设置状态的方法:

/**@REQUIRE: None;
* @MODIFIES: status;
* @EFFECTS:
* (s == 3) ==> status == Status.STILL;
* (s == 0) ==> status == Status.SERVE;
* (s == 2) ==> status == Status.WAIT;
* (s == 1) ==> status == Status.GOTORDER;
* @ THREAD_EFFECTS:\locked();
*/

  

以上的规格感觉应该是合理的,就是觉得有点丑,所以稍微改了一下(可能还是很丑):

    /**@REQUIRE: None;
* @MODIFIES: status;
* @EFFECTS:
(s == 3) ==> status == Status.STILL ||
(s == 0) ==> status == Status.SERVE ||
(s == 2) ==> status == Status.WAIT ||
(s == 1) ==> status == Status.GOTORDER;
* @ THREAD_EFFECTS:\locked();
*/  

(2)以下是我出租车类中的设置目标点的规格:

    /**
* @ MODIFIES: to;
* @ EFFECTS:
* this.to == to;
* @ THREAD_EFFECTS:\locked();
*/  

而这个方法的实现是这样的:

    public synchronized void setTo(Point p) {

        to.setLocation(p.x, p.y);
}

很明显这个规格的REQUIRE是要写的,所以改进如下:

   /**@ REQUIRES: p != null;
* @ MODIFIES: to;
* @ EFFECTS:
* this.to == to;
* @ THREAD_EFFECTS:\locked();
*/

(3)以下是我周期为7.5s的监控线程的构造方法 ,同理其REQUIRE也有问题:

   /**
@ MODIFIES: TIME; taxi; from; to; num;
@ EFFECTS:
this.TIME == TIME; this.taxi == taxi;
this.num == num; this.from == from;
this.to == to;
*/

 改进:

   /**@REQUIRE: taxi != null; from != null; to != null; TIME >= 0;
@ MODIFIES: TIME; taxi; from; to; num;
@ EFFECTS:
this.TIME == TIME; this.taxi == taxi;
this.num == num; this.from == from;
this.to == to;
*/  

(4)接下来是我调度类中的一个获取出租车信息的方法的规格:

    /**@ REQUIRES: str != {};
@ MODIFIES: None;
@ EFFECTS:
(\exist int i; 0 <= i < str.length; str.charAt(i) >= '0' && str.charAt(i) <= '9')
&& (\all int j; 0 <= j < i; str.charAt(j) < '0' || str.charAt(j) > '9')
&& (\exist int k; i <= k < str.length; str.charAt(k) >= '0' && str.charAt(k) <= '9')
&& (k+1 >= str.length || str.charAt(k+1) < '0' || str.charAt(k+1) > '9')
&& (\all int l; i <= l <= k; str.charAt(l) >= '0' && str.charAt(l) <= '9')
==> (\result == new Point(Integer.parseInt(str.substring(i, k+1), k+1)));
*/

  乍一看感觉很合理,但是仔细看却发现有错误:比如第一个逻辑表达式中定义的i的作用域只有第一行代码,并不能被后面的代码所识别,改进如下:

    /**@ REQUIRES: str != {};
@ MODIFIES: None;
@ EFFECTS:
(\exist int i; 0 <= i < str.length; (str.charAt(i) >= '0' && str.charAt(i) <= '9'
&& (\all int j; 0 <= j < i; str.charAt(j) < '0' || str.charAt(j) > '9')
&& (\exist int k; i <= k < str.length; str.charAt(k) >= '0' && str.charAt(k) <= '9')
&& (k+1 >= str.length || str.charAt(k+1) < '0' || str.charAt(k+1) > '9')
&& (\all int l; i <= l <= k; str.charAt(l) >= '0' && str.charAt(l) <= '9'))
==> (\result == new Point(Integer.parseInt(str.substring(i, k+1), k+1)));
*/

  改进之后就可以改变上面的不足。

(5)接下来是我十一次作业的特殊出租车的构造方法:

    /**@REQUIRES:
* No >= 0 && No < 100; mi != null; taxigui != null;
* @MODIFIES:
* No; mi; taxigui;
* @EFFECTS:
* this.mi == mi; this.taxigui == taxigui; this.No == No;
*/

  这个规格和第四个规格类似,都感觉是合理的,却有一点点小问题,传进来的taxigui不能保证是合法的,所以REQUIRE得重写,改进如下:

    /**@REQUIRES:
* No >= 0 && No < 100 && mi != null && taxigui != null && taxigui.repOk();
* @MODIFIES:
* No; mi; taxigui;
* @EFFECTS:
* this.mi == mi; this.taxigui == taxigui; this.No == No;
*/

基本思路和体会

这几次作业的规格都是在完成代码之后添加的,所以不一定合乎要求,不过在实验课上尝试了先写规格再写代码,觉得这样的模式也还行,不过这就对设计的要求高了一些,如果一开始设计有误,会浪费更多时间。

最后一次oo的代码作业,好像并没有什么特别的感觉,以后终于有更多时间做其他事情了,开心。

OO作业总结(三)的更多相关文章

  1. OO作业第三单元总结

    目录 一.JML语言理论基础及应用工具链 二.部署JMLUnitNG,自动生成测试用例 三.架构设计 第一次作业 第二次作业 第三次作业 四.Bug分析 五.心得体会 一.JML语言理论基础及应用工具 ...

  2. 北航oo作业第三单元小结

    一.梳理JML语言的理论基础 1.jml的注释结构 jml注释语言的每一行都以@作为开始,若是块注释,则需要在注释块的首尾使用/*@ 与@*/ 2.jml的表达式体系 1.原子表达式 表达式可以看作是 ...

  3. 【作业】HansBug的前三次OO作业分析与小结

    OO课程目前已经进行了三次的作业,容我在本文中做一点微小的工作. 第一次作业 第一次作业由于难度不大,所以笔者程序实际上写的也比较随意一些.(点击就送指导书~) 类图 程序的大致结构如下: 代码分析 ...

  4. 北航OO(2020)第三单元博客作业

    一.JML理论基础及相关工具链 1.JML理论基础 该部分梳理本单元作业中涉及到的JML知识. 1.1注释结构 JML采用javadoc注释的方式来表示规格,且每行以@开头.通过使用//@annota ...

  5. OO第三次博客作业--第三单元总结

    一.JML 语言的理论基础及应用工具链 JML 是一种行为接口规格语言,提供了对方法和类型的规格定义手段.通过 JML 和其支持工具,不仅可以基于规格自动构造测试用例,并整合了 SMT Solver ...

  6. 第十五次oo作业

    作业十五 测试与正确性论证的效果差异 程序的测试需要通过输入特定数据等方式,检查程序是否和预期相同,因为测试不可能穷举,导致了不穷举的测试不可能验证程序是完全正确的,只能验证程序在测试时没有发生错误, ...

  7. oo作业总结(四)

    测试与正确性论证 测试是通过构造一系列测试数据,通过对比程序的实际运行结果和预期输出结果来判断程序是否有bug的一种手段.同时,在测试的时候是默认看不到程序的具体实现的,即进行黑盒测试,例如每次OO作 ...

  8. oo作业总结(二)

    概述 和前三次作业相比,这几次作业最大的不同是难度的飞跃.遗憾的是在这难度的变化面前,我自己却没有做好充分的准备,错误的低估了作业难度导致给自己带来了很多不必要麻烦和损失.接下来我将对它们进行说明(度 ...

  9. oo作业总结(一)

    概述 经历了三次oo作业的洗礼,让我对java语言的强大以及面向对象编程有了初步的理解(当然,我是小白).本文接下来就将对自己这三次作业的代码进行分析以及分享自己的心路历程. 基础知识点考核 针对前三 ...

  10. oo作业总结报告

    oo第一次博客 以前从未真正的写过Java代码,接触Java也只是寒假的时候简单的看了看语法,不懂该如何面向对象,但没事,心里不惧,想着什么都是可以学的(直到真正开始写工程的时候,才发现自己还是太天真 ...

随机推荐

  1. 牛客OI周赛4-提高组 B 最后的晚餐(dinner)

    最后的晚餐(dinner) 思路: 容斥 求 ∑(-1)^i * C(n, i) * 2^i * (2n-i-1)! 这道题卡常数 #pragma GCC optimize(2) #pragma GC ...

  2. win10 java环境变量

    https://jingyan.baidu.com/article/fd8044fa2c22f15031137a2a.html

  3. 雷林鹏分享:jQuery EasyUI 树形菜单 - 使用标记创建树形菜单

    jQuery EasyUI 树形菜单 - 使用标记创建树形菜单 一个树形菜单(Tree)可以从标记创建.easyui 树形菜单(Tree)也可以定义在 元素中.无序列表的 元素提供一个基础的树(Tre ...

  4. 怎么从bam文件中提取出比对OR没比对上的paired reads | bamToFastq | STAR

    折腾这么多都是白瞎,STAR就有输出没有别对上的pair-end reads的功能 参见:How To Filter Mapped Reads With Samtools I had the same ...

  5. English trip EM2-PE-1B Teacher:Patirck

    PE = 演讲课 课上内容(Lesson) How are you today?  你今天怎么样? What is your name?  你的名字叫什么? What do you come from ...

  6. xsd与xml和类(class)对象之间的互相转换

    xsd与xml和类(class)对象之间的互相转换 . 第一:通过现有的已经写好的xsd来生成class(.cs)文件. 在您Visual Studio的安装目录下的SDKv2.0Bin中有个应用程序 ...

  7. Mysql 中如何创建数据库和数据表

    这里的数据库为:user  数据表为 aaa mysql –uroot –p                 进入mysql create database user;            创建数据 ...

  8. Power Of Two leetcode java

    问题描述: Given an integer, write a function to determine if it is a power of two. 问题分析:给定一个数,判断它是不是2的幂. ...

  9. 【Java】【8】StringUtils中isNotEmpty和isNotBlank的区别

    前言: 1,StringUtils.isNotEmpty(str)和StringUtils.isNotBlank(str)都是用来做非空判断的 2,通常用isNotBlank 3,import org ...

  10. 【MySQL】【3】String和Date相互转换

    正文: 1,Date转String --结果:<2019-04-10> SELECT DATE_FORMAT(SYSDATE(), "%Y-%m-%d") FROM D ...