2020.03.20软件构造听课笔记

设计规约

final关键字定义了设计决策,代表不可改变

为什么要写出“假设”?第一:自己记不住,第二:别人看不懂

代码中蕴含的“设计决策”:给编译器读
注释形式的“设计决策”:给自己和别人读

精确的规约有助于区分责任
客户端无需阅读调用函数的代码,只需理解spec即可

规约可以隔离“变化”,无需通知客户端
规约也可以提高代码效率(Eg.实现者不需要写代码确保是输入的正确性,调用者的责任)
规约:扮演“防火墙”角色
解耦,不需要了解具体实现

规约的内容:输入输出的数据类型,功能和正确性,性能,只讲“能做什么”,不讲“怎么实现”

前置条件:对客户端的约束,在使用方法时必须满足条件
后置条件:对开发者的约束,方法结束时必须满足的条件
契约:如果前置条件满足了,后置条件必须满足

前置条件满足,则后置条件必须满足
前置条件不满足,则方法可以做任何事情
“你违约在先,我自然不遵守承诺”

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

程序中可能有很多变量指向同一个可变对象(别名)
无法强迫类的实现体和客户端不保存可变变量的“别名”

规约的分类标准:规约的确定性,规约的陈述性,规约的强度,用于判断哪个规约更好

spec变强:更放松的前置条件+更严格的后置条件

欠定的规约:同一个输入可以有多个输出
非确定的规约:同一个输入,多次执行时得到的输出可能不同
欠定的规约通常有确定的实现(一旦实现确定之后,返回这也就确定了)

操作式规约,例如伪代码
声明式规约:没有内部实现的描述,只有“初-终”状态
声明式规约更有价值

内部实现的细节不在规约里呈现,放在代码实现体内部注释里呈现

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

一个好的“方法”设计,并不是你的代码写的多么好,而是你对该方法的spec设计的如何,一方面:Client用着舒服,另一方面:开发者编着舒服
Spec描述的功能应单一、简单、易理解
规约应该信息丰富
规约应该足够强,太弱的spec,Client不放心、不敢用(因为没有给出足够的承诺)
开发者应该尽可能考虑各种特殊情况,在post-condition给出处理措施
规约也应该足够弱,太强的spec,在很多特殊情况下难以达到,给开发者增加了实现的难度(client当然非常高兴)
在规约里使用抽象类型,可以给方法的实现与客户端更大的自由度
惯用的做法是:不限定太强的precondition,而是在postcondition中抛出异常:输入不合法
尽可能在错误的根源处fail,避免极大规模扩散

衡量标准:检查参数合法性的代价多大
归纳:是否使用前置条件取决于:
(1)check的代价
(2)方法的使用范围
如果只是在类的内部使用该方法(private),那么可以不使用前置条件,在使用该方法的各个位置进行check——责任交给内部client
如果在其他地方使用该方法(public),那么必须要使用前置条件,若client端不满足则方法抛出异常ss

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值