第五章--第二节:复用性的实施

第五章:面向软件构造的可复用性的构建方法

第二节:复用性的实施

问题一:设计可复用的类

1.行为子类型和LSP原则

    子类型多态:客户端可用统一的方式处理不同类型的对象

    子类型多态要遵守的原则:

  • 客户端可用统一的方式处理不同类型的对象
  • 子类型需要实现抽象类型中的所有未实现方法
  • 子类型中重写的方法必须有相同或子类型的返回值
  • 子类型中重写的方法必须使用同样类型的参数
  • 子类型中重写的方法不能抛出额外的异常

    方法中的LSP原则:更强的不变量、更弱的前置条件、更强的后置条件

**例:看下列子类是否满足LSP原则

父类:

第五章--第二节:复用性的实施

子类:

第五章--第二节:复用性的实施

(解:子类具有和父类一样的表示不变量,并且有额外的表示不变量,表示不变量没有变弱;并且重写的方法有相同的前置和后置条件,满足LSP)

**:看下列子类是否满足LSP原则

次父类:

第五章--第二节:复用性的实施

子类:

第五章--第二节:复用性的实施

(解:次父类的)**********************

2.LSP是一种对子类型关系的特殊的定义,被称为 强行为子类化

    要求:

  • 前置条件不能强化
  • 后置条件不能弱化
  • 不变量要保持
  • 子类型方法参数:逆变
  • 子类型方法的返回值:协变

问题二:Covariance (协变) 与 Contravariance (反协变、逆变)

    1. 协变Covariance

    父类型-->子类型:越来越具体specific

    返回值类型:不变或变得更具体

    异常的类型:也是如此。

例:

第五章--第二节:复用性的实施

第五章--第二节:复用性的实施

    2.  反协变、逆变Contravariance

    父类型-->子类型:越来越具体specific

    参数类型:要相反的变化,要不变或越来越抽象

例:

第五章--第二节:复用性的实施

    3.总结协变与逆变

第五章--第二节:复用性的实施

(1.子类型(属性、方法)关系;2.不变性,重写方法;3.协变,方法返回值变具体;4.逆变,方法参数变抽象;5.协变,参数变的更具体,协变不安全)

问题三:各种应用中的LSP

1.数组中协变(数组是协变的)

    第五章--第二节:复用性的实施

(在java的子类型规则中,一个T类型的数组,其中包含的元素可以是T类型也可以是T的子类型)

2.泛型中的LSP

  • ***第五章--第二节:复用性的实施

(注意:第一行符合子类型关系,而第二行不符合子类型关系)

(原因:因为在泛型中存在 类型擦出(type erasure))

(所以,泛型不是协变)

:???????????????

第五章--第二节:复用性的实施

第五章--第二节:复用性的实施

第五章--第二节:复用性的实施

  • 总结泛型中的LSP

第五章--第二节:复用性的实施

尽管Integer是Number的子类型,但Box<Integer>也不是Box<Number>的子类型

3.为了解决类型擦除的问题-----Wildcards(通配符)

第五章--第二节:复用性的实施

(?是一种不确定的类型)

    1.更低边界的通配符:第五章--第二节:复用性的实施

    2.更高边界的通配符:第五章--第二节:复用性的实施

    3.带有通配符的泛型的LSP:

  •     List<Number> is a subtype of List<?>
  •     List<Number> is a subtype of List<? extends Object>
  •     List<Object> is a subtype of List<? super String>
  • 第五章--第二节:复用性的实施
  • 第五章--第二节:复用性的实施

问题四:委派(Delegation)(复用的一种常见形式)

    1.委派:一个对象请求另一个对象的功能(“委托”发生在objet层面,而“继承”发生在class层面)

*例:继承与委派的对比

第五章--第二节:复用性的实施


    委派的类型:

  • Use(A use B) 
  • Composition/aggregation (A owns B)
  • Association (A has B)

    模型:

第五章--第二节:复用性的实施

①Use--临时性的delegation

第五章--第二节:复用性的实施

(直接在方法中委托其他类的对象,只是使用的其他类的对象,是临时的)

②Association--永久性的delegation

第五章--第二节:复用性的实施

(一个类有其他类的对象声明(has),是永久性的)

③Composition--更强的delegation

 

第五章--第二节:复用性的实施

(一个类有另一个类的对象声明(is part of),更是永久性的)

④Aggregation

第五章--第二节:复用性的实施

2.委派使用的情况

  •   如果子类只需要复用父类中的一小部分方法
  •   一个类不需要继承另一个类的全部方法,通过委托机制调用部分方法

问题五:组合(Composition)

    CRP原则:Composite Reuse Principle

**:一个公司要分红,但公司不同职位(经理、程序员、秘书)的分红不同(用继承和组合机制对比实现)

继承:

父类:

第五章--第二节:复用性的实施

子类:

第五章--第二节:复用性的实施

(但不同的人分红不同,所以每种职位都要重写父类中的方法,代码很赘余)

(核心问题:每个Employee对象的奖金计算方法都不同,在object层面而非class层面。)

组合:(CRP)

第五章--第二节:复用性的实施

更为一般的委派的设计:

第五章--第二节:复用性的实施


**:对比继承和 组合

继承:

第五章--第二节:复用性的实施

组合:

第五章--第二节:复用性的实施

问题六:两种模型

1.

第五章--第二节:复用性的实施

2.

第五章--第二节:复用性的实施