5.2 面向复用的软件构造技术


综述:本节从类、API、框架三个层面学习如何设计可复用软件实体的具体技术

1. 设计可复用的类

1.1 子类型多态和利斯科夫替换原则

  1. 子类型多态:客户端可用统一的方式处理不同类型的对象,例
    5.2 面向复用的软件构造技术
    在可以使用a的场景,都可以用c1和c2代替而不会有任何问题(但反过来不行,即不能用父类来实例化一个子类引用)
  2. java静态类型检查中的规则:
    1. 子类型可以增加方法,但不可删父类原有的方法
    2. 子类型需要实现抽象类型中的所有未实现方法
    3. 子类型中重写的方法必须有相同或子类型的返回值
    4. 子类型中重写的方法必须使用同样类型的参数(或该类型的父类型,但java中不支持,会自动默认为重载)
    5. 子类型中重写的方法不能抛出额外的异常
  3. 规约上的准则:
    1. 更强的不变量
    2. 更弱的前置条件
    3. 更强的后置条件
  4. 利斯科夫替换原则本质是强行为子类型化,其要求为:
    1. 前置条件不能强化
    2. 后置条件不能弱化
    3. 不变量要保持
    4. 子类型方法参数:逆变
    5. 子类型方法的返回值:协变
    6. 异常类型:协变
  5. 协变:子类型方法的返回值是其父类型方法的返回值的子类型,即子类型及其方法的返回值在各自的继承树上的相对位置是协同的
  6. 逆变:子类型参数的类型是其父类型方法的返回值的父类型,即子类型及其方法的参数在各自的继承树上的相对位置是相反的
  7. java遇到逆变时,当作overload(重载)处理
  8. 实例:数组类型
    5.2 面向复用的软件构造技术
  9. 泛型中的LSP原则
    1. 泛型是类型不变的,不是协变的
    2. 泛型声明时存在类型擦除,即尖括号里面的内容只在编译时被考虑,运行时不考虑
    3. 实例:5.2 面向复用的软件构造技术
    4. 简单来说,尖括号里面的类型和其它尖括号里面的类型即使有直接继承关系,但对于整个泛型是没有继承关系的
    5. 可以用通配符来解决泛型继承的问题<?>,<? extends AClass>,<? super BClass>
      5.2 面向复用的软件构造技术

1.2 委托和组合

1.2.1 java排序实例

  1. 如果ADT需要比较大小,或者要放入Collections或Arrays进行排序,可实现Comparator接口并override compare()函数。
    5.2 面向复用的软件构造技术
  2. 另一种方法:让ADT实现Comparable接口,然后overridecompareTo() 方法,与使用Comparator的区别:不需要构建新的Comparator类,比较代码放在ADT内部。
    5.2 面向复用的软件构造技术

1.2.2 委托(Delegation)

  1. 委派/委托:一个对象请求另一个对象的功能,是复用的一种常见形式。
  2. 委托可以被描述为在实体之间共享代码和数据的低级机制
    5.2 面向复用的软件构造技术
  3. 委托依赖于动态绑定,因为它要求给定的方法调用可以在运行时调用不同的代码段。
  4. 委托和继承的比较:
    1. 继承:通过新操作扩展基类或覆盖操作。
    2. 委托:把基类拿过来作为新的类的元素,可以用基类以实现的功能扩展新类的功能
    3. 委托可以替代继承的情况:如果子类只需要复用父类中的一小部分方法,可以不需
      要使用继承,而是通过委派机制来实现

1.2.3 组合继承原则

  1. 类应该通过它们的组合实现多态行为和代码重用(通过包含实现所需功能的其他类的实例),而不是从基类或父类继承。
  2. 组合原则:
    1. 使用接口定义系统必须对外展示的不同侧面的行为,例如,一只鸟可以叫也可以飞,那么可以定义两个接口,quackable和flyable。
    2. 接口之间通过extends实现行为的扩展(接口组合)。然后可以定义一个接口birdable同时继承了上述两个接口,这样这个新的接口就有了上述两个接口的全部功能。
    3. 类implements 组合接口,从而规避了复杂的继承关系。接下来,我们定义的“鸟类”就可以实现birdable,使得活动顶层接口的功能(在构造实例的过程中,同时要delegation顶层功能的接口)

1.2.3.1 Dependency: 临时性的delegation

  1. Dependency:对象需要其他对象(供应商)实现的临时关系。
  2. 本质上就是通过方法的参数列表把被委托方传进来,或者通过在方法中定义局部变量来产生委托方。临时要用被委托方的方法,在被委托方中的field中并不保存。
  3. 实例:5.2 面向复用的软件构造技术

1.2.3.2 Association: 永久性的delegation

  1. Association:对象类之间的持久关系,允许一个对象实例使另一个对象实例代表它执行操作。
  2. 被委托方常为委托方的属性
  3. 实例:
    5.2 面向复用的软件构造技术

1.2.3.3 Composition: 更强的delegation

  1. Composition是一种将简单对象或数据类型组合成更复杂的对象的方法。
  2. 它的特点是,被委托方初始化是在委托方的内部
  3. 实例:
    5.2 面向复用的软件构造技术

1.2.3.4 Aggregation

  1. 对象存在于另一个之外,在外部创建,它作为参数传递给construtor
  2. 它的特点是,当委托方的对象被删除后,被委托方的实例仍然存在
  3. 实例:
    5.2 面向复用的软件构造技术