栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【哈工大软件构造】设计规约&注释应该怎么写?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【哈工大软件构造】设计规约&注释应该怎么写?

什么是规约

        规约是软件构造中一种常用的手段,它规定了每个方法的作用,是在编程之前对各部分模块的总体设计。规约在软件构造中起到了“防火墙”的作用,调用它的客户端不需要知道这个方法是如何实现的,实现者也不需要知道调用者用它做什么,起到了解耦的效果。

规约的内容与结构

规约的内容
  1. 输入/输出的数据类型。
  2. 功能和正确性期望。
  3. 性能要求。

规约的结构
  • 前置条件:对客户端的约束,在使用方法时必须满足的条件。
  • 后置条件:对开发者的约束,方法结束时必须满足的条件。
  • 契约:如果前置条件满足了,后置条件必须满足;前置条件不满足,则方法可做任何事情,也就是“你违约在先,我自然不需要遵守承诺”。​​​​​

        当前置条件被违反时,说明客户端有bug, 尽管实现者没有义务提醒,但可通过快速失败使bug更容易被找到和修复,例如抛出异常。

行为等价性

        以下面两个函数为例,这两个函数都要求接受array和val两个参数,且val在array中只出现一次,返回val出现的索引。

static int findFirst(int[] array,int val){
    for(int i = 0; i < array.length; i++){
        if(array[i] == val){
            return i;
        }
    }
    return array.length;
}
static int findLast(int[] array,int val){
    for(int i = array.length; i > 0; i--){
        if(array[i] == val){
            return i;
        }
    }
    return -1;
}

         我们判断行为等价性,也就是判断这两个函数是否可以相互替换。我们可以看到,这两个函数在行为上是不同的,但是对于客户端来说,这两个函数都符合如下规约,因此它们是等价的:

 Java中的规约         Java中的静态类型声明是一种规约,可据此进行静态类型检查static checking。方法前的注释也是一种规约,但需人工判定其是否满足。         Java中方法参数写在 @param 后面,返回值写在 @return 后面,可能抛出的异常写在 @throws 后面。其中, @param 后面的是前置条件, @return 和 @throws 后面的是后置条件,例如上面的规约写成Java注释为:

可变方法的规约
  1. 除非在后置条件里声明过,否则方法内部不应该改变输入参数。
  2. 程序员之间应达成的默契:除非规约必须如此,否则不应修改输入参数。
  3. mutable对象会使规约复杂化。 
      可变对象会让简单的问题变复杂,例如 程序中可能有很多变量指向同一个可变对象,我们也 无法强迫类的实现体和客户端不保存可变变量 的“别名”,因而我们一般在规约中约定,方法的参数均为不可变对象,例如:

测试方法的规约 黑盒测试         依据规约设计测试用例,不考虑实现,同其他客户端一样,例如:

设计良好的规约 比较规约 规约的确定性

        规约的确定性指描述的输出是否确定。

规约的陈述性

        规约的陈述性指仅仅描述了输出,还是描述了计算过程(不应该这样做,这样相当于暴露了内部实现过程)。

规约的强度

        规约的强度用于判断哪种规约更好。

        规约的强度S2>=S1就可以用S2替换S1,规约的强度指更放松的前置条件和更严格的后置条件。也就是更少的要求,更多的承诺。

规约的要求 内聚的          规约描述的功能应单一、简单、易理解,例如如下的规约实际上描述了两件事,因而应该分开形成两个方法。 信息丰富的

         信息丰富指不能让客户端产生理解的歧义,例如如下规约:

        一旦返回null,无法判断是key不存在,还是key对应的值就是null。 规约应当足够强          太弱的规约,客户端不放心、不敢用 (因为没有给出足够的承诺),例如下图。 开发者应尽可能考虑各种特殊情况,在前置条件中给出处理措施。         例如该规约没有说明遇到null时应该对list如何处理,是否保留null? 规约应当足够弱                  太强的spec,在很多特殊情况下难以达到,给开发者增加了实现的难度。

         例如这是一个过强的规约,因为无法保证一定能打开这个文件,可能存在这个文件不存在和文件系统损坏等问题。

 规约应当使用抽象数据类型          在规约里使用抽象类型,可以给方法的实现体与客户端更大的自由度。

         在Java中,这里的抽象数据结构一般使用接口,例如这里应该把ArrayList改为List。

前置条件         不写前置条件,就要在代码内部进行检查。如果检查的代价太大,就在规约里加入前置条件, 把责任交给客户端。但是 客户端不喜欢太强的前置条件,因为不满足前置条件的输入会导致失败。          惯用做法是: 不限定太强的precondition,而是在postcondition中抛出异常:输入不合法(尽可能在错误的根源处抛出异常,避免其大规模扩散)。         是否使用前置条件取决于(1) check的代价;(2) 方法的使用范围。
  1. 如果只在类的内部使用该方法(private),那么可以使用前置条件(方法内部 )不需要判断输入是否满足,认为客户端会保证前置条件),在使用该方法的各个位置进行检查——责任交给内部客户端。
  2. 如果在其他地方使用该方法(public),那么可以不使用/放松前置条件(在方法内部检查输入是否满足),若client端不满足则方法抛出异常。
        

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/888729.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号