HIT SC ADT and OOP

ADT: Abstract Data Types

在上学期的数据结构中我们已经接触过ADT——抽象数据型,抽象数据型是一个数学模型和在该模型上定义的操作的集合。在软件构造中ADT概念也类似,不过多了些值得注意的点,首先看一下MIT官网列出的几个点:

抽象性(abstraction):省略或隐藏低层次细节以获得更简约更高层次的idea。(Omitting or hiding low-level details with a simpler, higher-level idea.)

模块化(Modularity:将一个系统划分为组件或模块,每个组件或模块都可以与系统的其他部分分开设计、实现、测试、推理和重复使用。(Dividing a system into components or modules, each of which can be designed, implemented, tested, reasoned about, and reused separately from the rest of the system.

封装(Encapsulation:在模块周围筑起一道“墙”,使模块对自己的内部行为负责,系统其他部分的错误不能破坏其完整性。(Building a wall around a module so that the module is responsible for its own internal behavior, and bugs in other parts of the system can’t damage its integrity.

信息隐藏(Information hiding:将一个模块的实现细节从系统的其他部分隐藏起来,这样以后可以在不改变系统其他部分的情况下改变这些细节。(Hiding details of a module’s implementation from the rest of the system, so that those details can be changed later without changing the rest of the system.

Separation of concerns不知道怎么翻译,可能是各司其职吧):使一个功能成为单一模块的责任,而不是将其分散到多个模块。Making a feature (or “concern”) the responsibility of a single module, rather than spreading it across multiple modules.

在我看来,ADT就是模板,比接口更抽象的东西,与具体实现无关,这也是ADT最重要的特性。

The operations of ADT

ADT的四种操作为:构造器、生产器、观察器、变值器,数学化的描述如下:

然后老师上课提了一嘴,生产器和构造器有时候一样,主要是发生在实际作用于返回值的类型没有在参数体现。然后mutator这个操作,只有mutable类有,immutable是没有的,这点对我们后面的学习会产生很大的影响,实际上Java提供的对应的mutableimmutable类也是通过控制mutator实现。

An abstract type is defined by its operations

这里的基本思想是,一个ADT是由它的操作来定义的。一个类型T的操作集,以及它们的规格,完全表征了我们对T的含义。

扩展我们对spec firewall的比喻,你可以把抽象类型的值想象成硬壳,不仅隐藏单个函数的实现,而且隐藏一组相关的函数(该类型的操作)和它们共享的数据(存储在该类型值中的私有字段)。

该类型的操作构成了它的抽象性。这是public的,对使用该类型的客户可见。

实现该类型的类的字段,以及帮助实现复杂数据结构的相关类,构成了一个特定的表示。这一部分是private的,只对类型的实现者可见。

表示独立性(Rep Independence)

关键的是,一个好的ADT应该是表示独立的。这意味着ADT使用与它的表示方式(用于实现它的数据结构)无关,因此表示方式的变化对抽象类型本身以外的代码没有影响。例如,数组提供的操作与数组在内部是否被表示为一个连续的内存块、一个链表或一个哈希表无关。

作为一个实现者,只有当ADT的操作被完整地指定为先决条件(pre-conditions)和后决条件(post-conditions)时,你才能安全地改变ADT的表示,这样客户就知道要依赖什么,你也知道你可以安全地改变什么。

抽象函数(Abstract Function)与表示不变量(Rep Invariant)

抽象函数将R空间的值与A空间的值对应起来,并且必须是满射,必须满足客户看到的所有值都有对应。AF并不单单取决于RA

表示不变量:RI:R->booleanRI的定义为:RI(r)=true 当且仅当 rAF匹配。因此,一方面RI可以视作是R的一个子集;另一方面,AF的映射我更愿意将他描述为RI->A,因为只有RI里的值才能被匹配,更符合数学上函数的定义。我们可以编写checkRep函数来检查RI是否满足。

有益变值(Beneficent mutation):

对于immutable来说,一旦某个对象满足RI,就不会再有违背的可能性,因为没有mutator改变属性;对于mutable来说,mutator存在潜在改变RI的可能性,如果一个mutator从不改变一个R空间所对应的A空间值,则称为Beneficent mutation

Safety from exposure

书写这部分时,要从fieldsmethod两方面来考虑。比如fieldsprivate and final或者immutablemethod返回immutable或者对mutable fields进行defensive copy

再看规约:

返回来再看ADT的规约,如下图所示,事实上我们ADT规约指的就是图中clients所能见的那一部分:这包括参数、返回值和由其操作抛出的异常。每当spec需要引用ADT的值时,它应该将该值描述为抽象值,也就是抽象空间A中的数学值。

spec不应该谈论rep的细节,或者代表空间R的元素。它应该认为rep本身(私有字段)对客户不可见,就像方法体和它们的局部变量被认为是不可见的。这就是为什么我们把rep的不变性和抽象函数写成类的主体中的普通注释。

ADT也可以隐藏pre-conditions,因为依靠客户并不严格可靠。将pre-conditions隐喻于参数名中,或直接创建对应RIADT

How to establish invariants

为了保持不变量我们需要:初始创建对象时就让RI正确并且操作并不会改变RI。这意味着:constructorsproducers必须为新的对象实例建立RI;以及mutatorsobserversproducers必须为现有的对象实例保留该RI

规则如下:

如果一个ADTRI

1、由constructorsproducers建立。

2、被mutatorsobserversproducers所保留

3、没有发生表示暴露。

那么该不变性对该抽象数据类型的所有实例RI都是true的。

等价性:

这部分还蛮简单的,对immutable来说,有AF等价性,观察等价性;mutable来说有AF等价性、观察等价性、行为等价性。

Mutable的值得关注一下,行为等价性就是引用直接相等,与Objectsequals对应。不过mutable倾向于实现观察等价性。

也可以自己重写equals以实现不同需求,但是注意一定同时重写equalshashCode

差不多就这些吧,本身也是一边复习可能也有理解不准确的地方,恳请指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值