系列文章目录

哈工大软件构造课程知识点总结(一)
哈工大软件构造课程知识点总结(二)
哈工大软件构造课程知识点总结(三)
哈工大软件构造课程知识点总结(四)
哈工大软件构造课程知识点总结(五)
哈工大软件构造课程知识点总结(六)


文章目录

  • 系列文章目录
  • 简介
  • Chapter 5:Designing Specification
    • 规约简要介绍
    • 行为等价性
    • 规约的设计
    • 规约的比较
    • 规约画图
    • 如何设计好的规约
  • Chapter 6:Abstract Data Type
    • 抽象数据类型相关概念
    • 设计抽象数据类型
    • 测试抽象数据类型
    • 表示独立性
    • 表示不变性
    • 抽象函数
    • 表示不变性(RI)与抽象函数(AF)之间的关系
      • 表示泄露
    • 有益的可变性

简介

此文章是2021春哈工大软件构造课程Chapter 5、Chapter 6的知识点总结。

Chapter 5:Designing Specification

规约简要介绍

“方法”是程序的积木,可以被独立开发、测试、复用。使用“方法”的客户端,无需了解内部的具体实现,这就是“抽象” 的思想。
一个完整的方法应包含规约实现两大部分,如下图示例:

代码本身就蕴含着“设计决策”(如使用final关键字说明此变量不可变),但这远远不够。我们需要注释形式的“设计决策”(规约)以供自己和他人阅读。

规约(spec)给程序员和用户双方都确定了责任,调用时双方都要遵守。

规约的作用:

  • 隔离“变化”,无需通知客户端——“防火墙”
  • 解耦,客户端不需了解具体实现
  • 提高代码效率


规约的内容:

  • 输入/输出的数据类型
  • 方法的功能和正确性
  • 性能

只讲“能做什么”,不讲“如何实现”!

行为等价性

根据代码的规约,站在客户端视角看行为等价性。
例: 有以下两个方法:

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

对于以下规约:

由于两个函数都符合此规约,故此情况下它们等价。

规约的设计

前置条件(precondition):对客户端的约束,客户端使用方法时必须满足的条件,使用关键词requires表明。
后置条件(postcondition):对开发者的约束,方法结束时必须满足的条件,使用关键词effects表明。

  • 静态类型声明是一种规约,可据此进行静态类型检查(static checking)
  • 方法前的注释也是一种规约,但需人工判定其是否满足

契约:如果前置条件满足了,后置条件必须满足;前置条件不满足,则方法可做任何事情(最好还是处理一下,通过failing fast让客户端发现这一问题)。

规约具体设计规则:

  • 参数使用@param描述,结果使用@return@throws描述
  • 如果可能,将前置条件写入@param中,后置条件写入@return@throws
  • 除非在后置条件中声明过,否则方法内部不应该改变输入参数
  • 尽量不设计修改输入参数的规约,减少使用可变对象
  • 描述的功能要单一、简单、易理解
  • 如果规约中需要提到“值”,只能使用抽象空间中的“值”(关联Chapter 6)

一个具体的规约:

补充Chapter 2 黑盒测试部分:
测试用例不能依赖于具体实现,而必须同客户端一样,遵守规约
出处:Chapter 5 课件 P46

规约的比较

可从规约的确定性、陈述性及强度入手进行比较。
假如规约强度S2 >= S1,则有:

  • 前置条件S2比S1更弱或相同
  • 后置条件S2比S1更强或相同

较强的规约具有更放松的前置条件 + 更严格的后置条件

例:
(1)以下三个规约依次增强:

(2)以下两个规约无法比较强度


相较于第一个规约,第二个的前置条件更弱了;但在满足第一个规约的前置条件的情况下,第二个规约相较于第一个其后置条件也弱化了(没有返回最低索引值)。

当规约被增强时:

  • 可满足规约的实现方式更少
  • 更多的用户端可以使用
  • 实现者(开发者)的自由度更小,责任更重
  • 客户端(使用者)责任更轻

规约画图

以find为例:

可以得到以下结论:

  • 某个具体实现,若满足规约,则落在其范围内,否则,在其之外
  • 程序员可以在规约的范围内自由选择实现方式,客户端无需了解具体使用了哪个实现
  • 规约越强,对应的区域越小

如何设计好的规约

  • 规约不应太弱,也不能太强(权衡用户使用与实现难度)
  • 在规约里使用抽象类型,可以给方法的实现体与客户端更大的自由度
  • 是否使用前置条件取决于check的代价和方法的使用范围

Chapter 6:Abstract Data Type

抽象数据类型相关概念

抽象数据类型(ADT)强调“作用于数据上的操作”,程序员和客户端无需关心数据如何具体存储的,只需设计/使用操作即可。

抽象数据类型的特性:

  • 可能发生表示泄露
  • 抽象函数(abstraction function) [AF]
  • 表示独立性(representation independence) [RI]
  • 表示不变性(representation invariant)

抽象数据类型的操作分类:

  • 构造器(creator):t* → T,可能实现为构造函数或静态函数(工厂方法)
  • 生产器(producer):T+, t* → T
  • 观察器(observer):T+, t* → t
  • 变值器(mutator):T+, t* → void | t | T,通常返回void,也可返回非空(如本身、修改结果等)
    注:T代表抽象类型自身,t是其他类型,+表示类型出现一次或多次,*表示类型出现零次或多次。

例:

  • Integer.valueOf() – Creator
  • new ArrayList() – Creator
  • Arrays.asList() – Creator
  • String.concat() – Producer
  • BigInteger.mod() – Producer
  • String.toUpperCase() – Producer
  • List.size() – Observer
  • String.length() – Observer
  • Map.keySet() – Observer
  • List.addAll() – Mutator
  • BufferedReader.readline() – Mutator

设计抽象数据类型

规则:

  1. 设计简洁、一致的操作
  2. 要足以支持客户端的需要,且用操作满足需要的难度要低
  3. 选择表示空间与抽象空间,并在代码中写明选择及AF和RI
  4. 表示泄露的安全声明(safety from rep exposure)

注:AF、RI应在代码中以注释形式写出,而不能在Javadoc文档中,防止被外部看到而破坏表示独立性/信息隐藏。

后两条规则具体示例:
Chapter 6 课件 P82 ~ P84

测试抽象数据类型

  • 测试creators, producers, and mutators:调用observers来观察结果是否满足规约
  • 测试observers:调用creators, producers, and mutators等方法产生或改变对象,来看结果是否正确

风险:如果被依赖的其他方法有错误,可能导致被测试方法的测试结果失效!

表示独立性

client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部规约和客户端。

违反表示独立性的一个示例:

违反原因:ADT修改后客户端代码受影响(无法再使用get方法)

保持表示独立性的一个示例:

表示不变性

表示不变性(represetation invariant, RI)可以看作:

  • 某个具体的“表示”是否是“合法的”
  • 所有表示值的一个子集,包含了所有合法的表示值
  • 一个条件,描述了什么是“合法”的表示值

精确记录RI——rep中所有fields何为有效

使用checkrep()私有方法检查RI:

  • 在所有可能改变表示的方法内都要检查
  • Observer方法不改变表示,但以防万一建议也要检查

如何建立表示不变性:

  • 构造器和生产器在创建对象时要确保不变量为true
  • 变值器和观察器执行时必须保持不变性
  • 每个方法返回前,用checkRep()检查不变量是否保持

用ADT不变量可取代复杂的前置条件,相当于将复杂的前置条件封装到了ADT内部。

抽象函数

首先引入表示空间与抽象空间的概念:

抽象空间(A空间):客户端看到和使用的值
表示空间(R空间):ADT对于数据的内部表示
ADT开发者要同时关注抽象空间和表示空间,客户端只需关注抽象空间。

表示空间 → 抽象空间的映射关系:

  • 抽象空间的每个值一定有表示空间的值与其对应——满射
  • 一些抽象空间的值可能有多个表示空间的值与之对应——未必单射
  • 表示空间中某些值可能没有对应的抽象空间的值——未必双射

抽象函数(abstraction function, AF):表示空间和抽象空间之间映射关系的函数,即如何去解释表示空间中的每一个值为抽象空间中的每一个值。

精准记录AF——如何解释每一个表示空间的值(映射关系)

表示不变性(RI)与抽象函数(AF)之间的关系

  • 不同的内部表示,需要设计不同的AF和RI
  • 选择某种特定的表示方式R,进而指定某个子集是“合法”的(RI),并为该子集中的每个值做出“解释”(AF)——即如何映射到抽象空间中的值
  • 即使是相同的R、RI,也可能有不同的AF,即“解释不同”

例:
选择字符串作为字符集合的表示方式,一种可能的对应RI、AF如下:

public class CharSet {private String s;// Rep invariant:// s.length() is even// s[0] <= s[1] <= ... <= s[s.length()-1]// Abstraction function:// AF(s) = union of {s[2i], ..., s[2i+1]} for 0 <= i < s.length()/2

则有:

  • “ad”、“eeee”、"abcd"满足RI,“adad”、"abc"不满足RI
  • AF(“acfg”) = {a, b, c, f, g}
  • AF(“tv”) = AF(“ttuv”) = AF(“ttuuvv”)

表示泄露

“表示泄露”不仅影响表示不变性,也影响了表示独立性。
一旦发生,ADT内部表示可能在程序任何位置发生改变(而不是限制在ADT内部)。
除非迫不得已,否则不要把希望寄托于客户端上,ADT有责任保证自己的不变性,并避免“表示泄露”。
最好的办法就是使用immutable的类型,彻底避免表示泄露!

表示泄露的安全声明——给出理由,证明代码并未对外泄露其内部表示。

有益的可变性

对于不可变的抽象数据类型,它在抽象空间内的抽象值应是不变的,但其内部表示的表示空间取值是可以变化的。

:一个使用两个int型变量来表示分数(AF、RI略,表示的分数为numerator / denominator)的ADT,其toString()方法可以修改其内部表示(化简分数):

/*** @return 分数的可读字符串表示*/
@override
public String toString() {int g = gcd(numerator, denominator);/* 化简分数,以便输出人更易读的值 */numerator /= g;denominator /= g;if (denominator < 0) {numerator = -numerator;denominator = -denominator;}checkRep();return (denominator > 1) ? (numerator + "/" + denominator): (numerator + "");
}

注意: 这种mutation仅改变了表示空间的值,并未改变抽象空间的值,对于客户端来说是利用了”AF未必单射“,从一个表示空间值变成了另一个表示空间值,但这并不代表不可变的类中可以随意出现mutator方法!

哈工大软件构造课程知识点总结(三)相关推荐

  1. 哈工大软件构造课程知识点总结(一)

    系列文章目录 哈工大软件构造课程知识点总结(一) 哈工大软件构造课程知识点总结(二) 哈工大软件构造课程知识点总结(三) 哈工大软件构造课程知识点总结(四) 哈工大软件构造课程知识点总结(五) 哈工大 ...

  2. 哈工大软件构造课程知识点总结(二)

    系列文章目录 哈工大软件构造课程知识点总结(一) 哈工大软件构造课程知识点总结(二) 哈工大软件构造课程知识点总结(三) 哈工大软件构造课程知识点总结(四) 哈工大软件构造课程知识点总结(五) 哈工大 ...

  3. 哈工大软件构造期末知识点总结

    哈工大软件构造试题构成: 1.30-45分的选择题,10-20题 2.55-70分的简答与设计题,5-6题 考试知识点(不全面): 1.git工具的知识点 2.Java设计模式(一共有23个,主要考察 ...

  4. 2022哈工大软件构造课程总结与经验分享(复习指导)

    一.软构1-3讲 1.软件构造的多维度视图和质量目标 2.软件测试与测试优先的编程 3.软件构造过程与配置管理 二.软构4-8讲 4.数据类型与类型检验 5.设计规约 6.抽象数据类型 (ADT) 7 ...

  5. 哈尔滨工业大学软件构造课程笔记第三章第四节

    3.4 面向对象的编程(OOP) 1. 基本概念:对象.类.属性和方法 对象 现实世界中的对象有两个共同特征:它们都有状态和行为. 识别现实对象的状态和行为是开始考虑面向对象编程的好方法. 对于你看到 ...

  6. 哈工大18年春软件构造课程讨论题

    这是哈工大18年春软件构造课程(徐汉川老师)的讨论题目,少部分答案摘录自课件PPT和网上的资源(链接在文中给出).如有错误还望指出,谢谢. 一.在软件测试过程中,"测试用例的数目" ...

  7. 2022哈工大软件构造lab1小结(知识点)

    哈工大软件构造lab1小结 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 问题一 使用的库 异常处理机制 字符串内容检查 写入文件 问题二 problem 3:画一 ...

  8. 哈工大软件构造 复习

    哈工大软件构造试题构成: 1.30分的选择题 2.70分的简答题 2019考试知识点(重要的,但不涵盖全部考试范围): 1.git工具的知识点(没有考察命令行,考察的主要是git的演变及各部分的作用) ...

  9. 哈工大软件构造期末复习

    系列文章目录 哈工大软件构造期末复习(最终章) 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录 哈工大软件构造期末复习(最终章) 前言 一.github指令 ...

最新文章

  1. 引擎: 决定数据库存取数据的方式 = 不同的特点 = 不同的用户体验 数据类型: 规定了数据库可以存放哪些数据 约束: 限制存储数据的规则 键...
  2. mysql设计功能设置表_MySQL数据表的设计
  3. 随机森林算法 python_Python实现的随机森林算法与简单总结
  4. 数据库(4)——候选码和主键
  5. 腾讯云连续四年排名中国音视频解决市场第一,头部厂商中RTC增速第一
  6. 跨域:Response to preflight request doesn t pass access control check: No Access-Control-Allow-Origin
  7. python中的进制,python中的十进制到十六进制
  8. 使用Kmeans聚类分析对复杂的数据进行分类
  9. 系统学习NLP(十八)--文本分类概述
  10. python发送多人邮件没有展示收件人问题的解决方法
  11. Activiti实现流程定义的控制与修改
  12. 杯具啊,混合语言编程的弊端出现了,兼谈js的开发工具
  13. Spark worker内存不足导致任务失败,报错Likely due to containers exceeding thresholds, or network issues
  14. 多台路由器连接,实现全网可达
  15. LaTex: 多种方法实现图片复杂排列
  16. tomcat如何调优
  17. Android平板电脑上的APP应用程序设计须知
  18. wordpress美化插件
  19. 1016: 银行利率 Python
  20. [POI2013] MOR-Tales of seafaring

热门文章

  1. 【RocketMQ】消息重试、重试次数设置、死信队列
  2. 云之讯手机号短信验证
  3. 2021安徽省高考成绩排名查询,2021年安徽高考成绩排名查询系统,安徽高考位次排名表...
  4. Rust Tokio hyper 协程下载文件工具
  5. java编程的一个猜数字有趣小游戏
  6. 平面解析几何----椭圆中焦中三角形的最值问题
  7. 使用Java计算生辰八字五行属性
  8. 部署Kubernetes集群(二进制 v1.18.8版)
  9. 家用双wan口路由器推荐_请推荐双WAN口的有线千兆硬路由器?
  10. 2021年7月中国编程语言排行榜