软件构造感想6

ADT和OOP中的“等价性”

等价关系

等价关系需要满足:对称性,自反性,传递性

不可变的等价

AF映射到同样的结果,则等价
站在外部观察者角度:对两个对象调用任何相同的操作,都会得到相同的结果,则认为这两个对象是等价的。 反之亦然

“==”与equals

在Java中,“==”意味着二者的引用是相同的,即指向同一个地址;而equals指的是对象等价性,即在某种程度上二者可以看做相同的,但不一定是同一个地址的内容
注:

  • == 对基本数据类型,使用==判定相等 
  • 对对象类型,使用equals() 而如果用==,是在判断两个对象身份标识 ID是否相等(即指向内存里的同一段空间)

equals的实现

在Java中尽量选择多态的方法而不是instanceof
多态优点:

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

多态存在的三个必要条件:继承,重写,父类引用指向子类对象

对象的相等

等价的对象必须有相同的hashCode (除非你能保证你的ADT不会被放入到Hash类型的集合类中 )
不相等的对象,也可以映射为同样的hashCode,但性能会变差

可变类的相等

观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致
行为等价性:调用对象的任何方法都展示出一致的结果

对可变类型来说,往往倾向于实现严格的观察等价性, 但在有些时候,观察等价性可能导致bug,甚至可能破坏RI
如果某个mutable的对象包含在Set集合类中,当其发生改变后,集合类的行为不确定 ;并且在JDK中,不同的 mutable类使用不同的等价性标准不同
对可变类型,实现行为等价性即可, 也就是说,只有指向同样内存空间的objects,才是相等的。所以对可变类型来说,无需重写这两个函数,直接继承 Object的两个方法即可。如果一定要判断两个可变对象看起来是否一致,最好定义一个新的方法。

可复用性的度量、形态与外部表现

软件复用

面向复用编程:开发出可复用的软件
基于复用编程:利用已有的可复用软件搭建应用系统
很大的适应性→降低成本和开发时间
充分的测试→高可靠、标准化、一致化
针对性不强→性能差

可复用性等级

最主要的复用是在代码层面 ,但软件构造过程中的任何实体都可能被复用
白盒复用:源代码可见,可修改和扩展
白盒框架,通过代码层面的继承进行框架扩展

  • 复制已有代码当正在开发的系统,进行修改
  • 可定制化程度高
  • 对 其修改增加了软件的复杂度,且需要对其内部充分的了解

黑盒复用:源代码不可见,不能修改
黑盒框架,通过实现特定接口/委托进行框架扩展

  • 只能通过API接口来使用,无法修改代码
  • 简单,清晰
  • 适应性差些

可复用的外部观察

类型可变、功能分组、实现可变、表示独立、共性抽取
类型可变(泛型):适应不同的类型,且满足LSP
实现可变:ADT有多种不同的实现,提供不同的re和 、af,但具有同样的specification (pre-condition, postcondition, invariants),从而可以适应不同的应用场景:即 提供完备的细粒度操作,保证功能的完整性,不同场景下复用不同的 操作(及其组合),并且内部实现可能会经常变化,但客户端不应受到影响。
注意表示独立性、信息隐藏
将共同的行为(共性)抽象出来,形成可复用实体:父类、抽象类,或者说只要看到自己写了重复的或相似的代码, 想办法抽取出来形成可复用方法/类

面向复用的软件构造技术

LSP

  • 子类型可以增加方法,但不可删
  • 子类型需要实现抽象 类型中的所有未实现方法
  • 子类型中重写的方法必须有相同或子类型的返回值或者符合co-variance的参数
  • 子类型中重写的方法必须使用同样类型的参数或者符合contra-variance的参数
  • 子类型中重写的方法不能抛出额外的异常

总结: 更强的不变量, 更弱的前置条件 ,更强的后置条件
强行为子类型化

  • 前置条件不能强化
  • 后置条件不能弱
  • 子类型方法参数:逆变
  • 子类型方法的返回值:协变 (子类型的方法不应抛出新的异常,除非这些异常本身是超类型的方法所抛出的异常的子类型。 )

委托与继承

委派/委托:一个对象请求另一个对象的功能,是复用的一种常见形式

  • 显式委托:将发送对象传递给接收对象
  • 隐式委托:通过语言的成员查找规则

通过inheritance实现对某些通用行为的复用的缺点:需要针对“飞法”设计复杂的继承关系树;不能 同时支持针对“叫法”的继承;动物行为发生变化时, 继承树要随之变化。
使用接口定义系统必须对外展示的不同侧面的行为,而接口之间通过extends实现行为的扩展(接口组合)类implements 组合接口 从而规避了复杂的继承关系
临时委托:两个类之间的这种关系形式称为“使用关系”,其中一个类在不实际将其合并为属性的情况下使用另一类。
永久委托:对象类之间的持久关系,它允许一个对象实例促使另一个对象实例代表其执行操作。一个类具有另一个作为属性/实例变量–这种关系是结构性的,因为它指定一种对象与另一种对象相连,并且不表示行为。

设计API

白盒框架:使用子类/子类型—继承

  • 允许扩展每个非私有方法
  • 需要了解超类的实现
  • 一次仅一个扩展
  • 编译在一起
  • 经常被称为开发者框架

黑盒框架使用组合- 委派/组合

  • 允许扩展在接口中公开的功能
  • 仅需要了解接口
  • 多个插件–
  • 常提供更多的模块化
  • 可以单独部署(.jar,.dll等)
  • 通常被称为最终用户框架,平台
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值