(构造笔记)ADT与OOP

ADT与OOP

1. ADT(Abstract Data Tyoe)操作的四种类型

ADT操作主要分为四种:
构造器(creators):创造一个新的对象
生产器(producers):从一个已有的对象中生产出一个新的对象
观察器(observers):从一个抽象的对象类型中返回一个不同类型的对象
(很简单的栗子,就是各种getXX()方法……)
变值器(mutators):改变对象属性的方法。通常返回void(如果返回值为void则必然意味着他改变了对象的某些内部状态,也可能返回非空类型)
其中构造器和生产器可能会有些混淆,对于构造器而言,可能为实现的构造函数或者静态函数等,而对于生产器就是从现有的对象出发,产生一个新的对象。下面几个例子可以帮助理解一下:

img

2. 表示独立性(representation independence)

表示独立性:客户端(client)使用ADT时无需考虑其内部是如何实现的,ADT内部表示的变化不应影响外部的spec和客户端。

说白了就是不要客户端知道你代码的具体逻辑,他们只需要知道代码的输入应该是什么,给了合法的输入输出是什么就够了。

另外注意除非ADT操作指明了具体的前置后置条件,否则不能改变ADT的内部表示——spec规定了客户端域代码实现者(implementer)之间的契约。

当然说是不清楚的,还要给个栗子对吧:

img

可以看出在java doc中并没有说明代码内部是如何实现的(具体实现在这里不重要~),客户只需要知道这段程序做什么的,合法的输入会得到怎样的输出就足够了。

  1. 不变量(Invariants)、表示泄漏
不变量(invariants):

在任何时候都是正确的。应该由ADT来负责其不变量,与客户端的人和也行为无关。(生成一个‘person’对象总不能让客户端来设置person有两条腿吧,客户设为三条腿还好,万一设置成四五六七八条腿呢,多可怕!)

为什么需要不变量:保持程序的正确性,容易发现错误。

再多的口水也不及一个栗子呀:

首先这个是代码:

img

那么让我们看我们优秀的客户端是如何使用的:

img

天啊!这个混蛋为什么改了名字?!没错这条推特被人盗了……盗图气不气?

这也就引出了以下的概念:

表示泄漏(representation exposure):

其将代码内部的数据泄露给了客户端,这样不仅影响不变性,也影响了表示独立性(因为客户知道了你的代码内部的实现,那么他就可以对你的代码进行一些你不希望看到的操作。诶呀~真可怕!),当然官方的解释是:无法在不影响客户端的情况下改变其内部表示。(晦涩……)

或许你说那我把变量修饰为private,然后在加上final,这样变不了了吧。然而……呵呵哒

我们还是看个例子吧:

img

注意红线部分,此处Date是一个mutable的类型,这样用确实对于该成员变量的引用不会改变。然而对于它内部的值呢?

img

看此时的快照图:

img

就算你是final修饰又如何?骨子里善变,该变还是要变的。所以对于这种mutable变量,防御式拷贝也就起了重要的作用:

img

这样就万事大吉啦,另外构造方法处也要记得修改。当然在上一节已经详细说明了,就不再赘余了……

  1. 表示不变量RI、抽象函数AF

    首先先来介绍一下表示空间R与抽象空间A:
    表示空间(the space of representation values):表示值(rep 值)的空间,由实际实现实体的值组成。一般情况下ADT的表示比较简单,有些时候也会用比较复杂的表示。
    抽象空间(the space of abstract values):抽象值构成的空间:用户看到和使用的值。
    ADT实现者关注表示空间R,用户关注抽象空间A。

注意:R->A必须是满射,但可以不是单射。

抽象函数:R与A之间的映射关系的函数。

表示不变量RI:某个具体的“表示”是否是“合法的”,也可以把RI看做所有表示值的一个子集,包含了所有合法的表示值或者看成描述了什么是“合法”的表示值的一个条件。

另外,不同的内部表示需要设计不同的AF和RI,选择某种特定的表示方式R,进而指定某个子集是“合法”得RI,并为该子集中的每个值做出一个“解释”AF——即如何映射到抽象空间中的值。

即使是同样的R、同样的RI,也可能有不同的AF,即“解释不同”。

设计ADT步骤:

选择表示空间R与抽象空间A
给出RI——合法的表示值
如何解释合法的表示值——映射AF

同样给出再多定义不如一道例题收获的多:

img

img

来解释一下这道例题:

第一个RI:s序列中的元素有小到大排序,而且不允许相同

第二个RI:s的长度为奇数,s序列中的元素有小到大排序,但允许相同

第三个RI:s序列中的元素不允许相同

第四个RI:null

现来看add方法:其在s后面添加了一个c字符,那么根据c的不同那么分别就不支持了第一二三个RI。

然后来看remove方法:注意,这个方法中只删除了第一个c,对于之后c不删除,所以如果s中存在重复字符,那么就不满足remove的spec。所以其只支持一三。

再来一个栗子:

img

乍一看好像四个都可以,但其实注意该方法的实现,这里遍历操作是一次扫描两个字符,所以当s为奇数个字符时,会出现空指针异常,所以只能选第二个。

总结:
不同的内部表示,需要设计不同的AF与RI。

选择某种特定的表示方式R,进而指定某个子集是合法的RI,并为该子集中的每个值做出解释”AF“即如何映射到抽象空间中的值。

同样的R、同样的RI,也可能有这不同的AF,即解释不同。
————————————————
版权声明:本文为CSDN博主「琴弦上的南柯合浦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37549266/article/details/80707151

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值