软构第八天:RI与AF(表示独立性相关内容)


前言

今天讲的内容十分抽象,接下来我将分享一下课程的内容与我自己听完课后的理解。

一、关键概念

什么叫rep?
直观来看,就是我们所实现的类中的一个个的属性。这里rep是representation的意思。
表示独立性
客户端在使用ADT时不需要考虑ADT内部的实现,我们对ADT内部的修改不会影响到外部spec和客户端的代码。除非我们的规约有明确说明pre-condition和post-condition,否则我们不能假定ADT采用的类型,比如一个Graph类型,我们不可以假设他内部是使用二维数组实现或是邻接矩阵实现,我们对Graph对象的使用仅限于其提供的方法。
具体案例如下:
在这里插入图片描述
这个Family类中定义的people属性使用List实现,但是我们在外面使用的时候直接调用了该属性,显然违反了我们表示独立性的原则,正确的做法应该是实现一个getMember函数,并且将public修饰属性改为用private final修饰。
不变量
我们在设计类的时候最好不要设计mutator方法。这样可以保证数据的安全性。这样由程序员来负责其不变量,与client端的任何行为无关。我们通过不变量来检查程序是否正确,发现一些问题。
在这里插入图片描述
上图这种调用会导致表示泄露,不仅影响不变性也影响了表示独立性,即无法在不影响客户端的情况下改变其内部表示。所以就像上文所述,我们将public改为private final即可。另外一种方法来处理返回的可变类型就是防御性复制,比如Date类型是可以被修改的,我们在类似getTime()函数中返回的就不能是原对象中的那个Date对象。
在这里插入图片描述
另外一个小trick:在设计类似mutator的功能时我们可以返回一个新的对象,以看到改变后的对象的内容,实际上这样实现更像是一种producer而不是mutator,因为这样很好地避免了修改原来的对象的值。

R vs. A Rep Invariant vs. Abstraction Function
下面是比较抽象的内容。
R是rep values构成的空间(即属性构成的空间)
A是抽象值构成的空间(即用户可以看到和使用的空间)

我们设计程序所关注的R到A的转换,其实就是相当于一个集合R经过状态转移函数δ变换到集合A。这个δ我们给它一个专有的名称即为AF(Abstract Function)。
通过以上的描述,我们很容易理解从R到A的映射必然是一个满射,因为A中的所有元素都是从R里面生成的,必然有对应;然而从R到A的映射不一定是一个双射,因为R中的元素可能不符合AF变换的条件,没办法产生对应的输出值,而且还有可能R中的多个元素经AF变换对应同一个A中的元素;另外显然R到A的映射不一定是单射(A中不会出现在R中找不到对应的元素)
在这里插入图片描述
下面我们说一下RI:R->boolean。RI其实就是在R集合上的一个操作,对于合法的R元素返回true,对于非法的R元素返回false。当然我个人感觉RI也可以看做是AF的反函数,不过输出并非R中元素,而是返回布尔值。
在这里插入图片描述

二、继续设计ADT

有了RI与AF等知识的概念,我们可以继续利用上述原则设计ADT。
在这里插入图片描述
我们需要随时检查RI是否满足,虽然这样可能会导致我们程序的运行时间很长。但是我们的首要原则是正确性,而程序性能优化是程序发布之前所需要做的。
在这里插入图片描述
此外我们需要在注释中给出比较精确的RI与AF的描述,来“自证清白”。

在这里插入图片描述

总结

今天所讲述的内容主要是有关R-RI-AF-A的一系列知识,当我们理解这些知识之后就会感觉他们都是很朴素的想法,一点也不神秘。但是只理解这些知识也是不够的,我们要将这些原则内化于心,在今后的开发实验中贯彻落实这些经验。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值