软件构造学习笔记第三章1

3.2设计规约
1.我们需要理解方法中的前置条件以及后置条件规范,并且可以写出正确的规范
2.什么是先决条件,什么是后置条件,他们各自是什么意思
3.理解欠定规约,非确定规约
4.理解说明性和操作性规约,并且能够写生命性规格
5.了解先决条件,后置条件和规约的强度,并且可以进行相互的比较
6.能够写出,有用的,适当的规范的规约

  1. 编程语言中的方法/函数
  2. 说明:为了互相沟通编程
    为什么需要有规范
    等价行为
    规范结构:前置条件和后置条件
    测试和验证规范
  3. 设计规范
    分类规范
    图表规范
    规格的质量
  4. 总结

二、编程语言中的函数和方法
参数部分
注意在调用方法-static时,参数类型不匹配的检查,这一部分的检查主要是在静态类型检查阶段完成的
返回值
需要注意返回值类型是否匹配,该部分也是在静态类型检查阶段完成
方法:积木
每一个程序都是由很多个小的方法构建起来的
方法可以独立开发,测试和复用
使用方法的客户端,不用了解方法内部如如何工作的,这就叫抽象

一个完整的方法包括
第一部分方法的规约说明
第二部分方法的具体实现

一、 说明:为了沟通编程

  1. 编程文档
    假设的记录
  2. 变量的数据类型定义(Java实际上会在编译时检查这个假设,并保证会这样做在你的程序中没有任何地方可以违背这个假设。)
  3. Final关键字定义了设计决策不可以更改(java也会静态检测的)
  4. 代码本身就有着你的设计决策,但远远不止
    2.为了交流编程
    1.我们为什么一定要写出假设?因为第一我们自己有时候记不住,第二别人看了看不懂
    2.编程的时候脑海里要有两个目标;要与电脑交流,代码中蕴含着设计决策,要给编译器读;要与他人交流,注释的设计决策
    3.规约和合约的方法
    规约有什么作用呢?
    没有规约,就没法写程序,就算你写出来了你也不知道对错啊
    规约是一个可以保证程序与客户端达成一致的一种契约
    规约给供需双方都确定了责任,在调用的时候双方都需要遵守
    为什么要有规约呢?
    实际情况,有很多bug来自于双方之间的误解;如果需求方不把需求写出来,可能和开发者的理解就不同;没有规约就难易定位错误,你连错哪都不知道
    有啥好处?精确地规约,有助于区分双方的责任;客户端无需阅读调用函数的代码只用理解说明就完事了

规约可以隔离变化,无需通知客户端;规约还可以提升代码的效率,规约扮演者防火墙的作用:它使得客户不会受到工作细节的影响,他屏蔽了实现的细节,这防火墙导致解耦,允许代码单元和要更改的客户端代码的独立地,只要变化尊重规范。解耦,不需了解具体实现

用户与对象的协议
输入/输出的数据类型;功能和正确性;性能
只讲“能做什么”,不讲 “怎么实现”
4.行为等价性
为了确定行为等价性,问题是我们是否可以用一种实现替换另一种实现吗
这两个函数是否等价?
行为不同,但对用户来说“是否等价”?
得出结论我们需要站在客户端视角看行为等价性!
与此同时可以根据规约 判断是否行为等价
如果两个函数复合规约,那么他们就等价

结论:单纯的看实现代码,并 不足以判定不同的 implmentation是否是 “行为等价的,需要根据代码的spec (开发者与client之间 形成的contract)判定 行为等价性,在编写代码之前,需要 弄清楚spec如何协商形 成、如何撰写
5.规范结构:前置条件和后置条件
前置条件:对客户端的约束,在使用方法时必须满足的条件
后置条件:对开发者的约束,方法结束时必须满足的条件
契约:如果前置条件满足了,后置条件必须满足

前置条件满足,则后置条件必须满足。
整体结构是符合逻辑的
暗示:如果前提条件成立
方法被调用,然后是后置条件方法完成时必须保持。

前置条件不满足,则方法可做任何事情。
– “你违约在先,我自然不遵守承诺”整体结构是符合逻辑的
暗示:如果前提条件成立
方法被调用,然后是后置条件
方法完成时必须保持。
不受后置条件的约束。
它是自由的,做任何事,包括不终止,抛出异常,返回任意的结果,任意的修改等。

Java规范
静态类型声明是一种规约,可据此进行 静态类型检查static checking。
方法前的注释也是一种规约,但需人工判定其是否满足
把先决条件扔进@param然后把后置条件放入@return 和 @throws.
参数由子句@param描述, 结果为由@return 和@throws.子句描述。

方法的规范可以讨论参数和返回
方法的值,但它不应该谈论的局部变量
方法的类的方法或私有字段。
-你应该考虑实现对规范的读者是不可见的。
-在Java中,该方法的源代码往往是不可用的
您的规范,因为Javadoc工具从您的
编码并将它们呈现为HTML。

注意点:
1…除非在后置条件里声明过,否则方法内部不应该改变输入参数
2. 应尽量遵循此规则,尽量不设计 mutating的spec,否则就容易引发bugs。
3. 程序员之间应达成的默契:除非spec必须如此,否则不应修改输入参数、
4. 尽量避免使用mutable的对象
为啥要避免mutable呢?
程序中可能有很多变量指向同一个可变对象(别名)
无法强迫类的实现体和客户端不保存可变变量 的“别名”
涉及可变对象的契约现在依赖于好的方面
每个具有对可变对象的引用的人的行为。
不能靠程序员的“道德”,要靠严格的“契约”

如何对规约进行测试
白盒测试用不着规约
黑盒测试需要规约,根据输入输出来进行测试
写测试用例的时候不要违背规约

如何设计规约

  1. 规约的分类
    规约的确定性
    规约的陈述性
    规约的强度
    使用规约的强度来判断规约的好坏
    那么什么是规约的强弱呢?
    现有两个规约s1,s2,假设s2规约强于s1
    如果S2要强,就意味着可以直接拿来满足弱的规约s1
    规约限制了输入的参数是什么样的,返回的值是什么样的
    通过比较两者的前置条件与后置条件来判断
    前置条件弱的输入限制变少,前置条件弱的规约强度高
    后置条件强的输出限制变多,后置条件强的规约强度高

越强的规约,意味着implementor的自由度和责任越重,而client的 责任越轻。
强的规约意味着输入更多,返回信息更加明确
写程序时更加难写,实现变少
对于用户可以输入更多的信息,可以使用的用户变多了

程序员可以在规约的范围内自由选择实现方式
客户端无需了解具体使用了哪个实现
强的规约圈圈小
弱的规约圈圈大

如何判断你的规则写的好呢?
一个好的“方法”设计,并不是你的代码写的多么好,而是你对该方
法的spec设计得如何。
– 一方面:client用着舒服
– 另一方面:开发者编着舒服
考试是给出规约让你进行分析
分析点一,一个好的规约应该是内聚的
Spec描述的功能应单一、简单、易理解
分析点二,信息丰富
不能让客户端产生理解的歧义
分析点三,规约应该足够强大
太弱的spec,client不放心、不敢用 (因为没有给出足够的承诺)。
开发者应尽可能考虑各种特殊情况,在post-condition给出处理措施。
分析点四,规约也别太强了
太强的spec,在很多特殊情况下难以达到,给开发者增加了实现的难 度(client当然非常高兴)。
分析点五,在规约里使用抽象类型,可以给方法的实现体与客户端更大的自由度别给的太具体
分析点六,前置条件和后置条件:是否应该使用前置条件?在方法正式执行之前,是否要检 查前置条件已被满足?
衡量标准:检查参数合法性的代 价多大?
归纳:是否使用前置条件取决于(1) check的代价;(2) 方法的使用范围 – 如果只在类的内部使用该方法(private),那么可以不使用前置条件,在使用 该方法的各个位置进行check——责任交给内部client; – 如果在其他地方使用该方法(public),那么必须要使用前置条件,若client端 不满足则方法抛出异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值