天天看点

软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术

文章目录

  • 4.1 可复用性的度量、形态与外部表现
  • 4.2 面向复用的软件构造技术
    • 1. 设计可复用的类
      • 1.1 LSP具体细则
    • 2. 泛型相关的子类父类(*)
    • 3. 继承和委托

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

注:最主要的复用在代码层面,但是其余例如测试用例、文档等也都可能被复用

  1. 为什么需要可复用性?

    降低成本、可靠性强

  2. 可复用性衡量

    复用机会是否频繁、复用场合个数、复用代价多少

  3. 白盒复用:

    通过继承复用

    缺点:增加了软件的复杂度

  4. 黑盒复用

    通过委托复用

    缺点:效率较低、适应性差

  5. 分层级复用

    基于代码层级的复用

    基于模块层级(类)的复用

    基于库文件的复用

    基于framework层级的复用——领域知识的复用

  6. 可复用性的原则
    1. 类型可变(泛型)
    2. 实现可变:ADT有不同的实现,提供不同的representations和abstract functions,但具有同样的spec(precondition、postcondition)
    3. 方法的聚集和分处
    4. 表示独立性、信息隐藏
    5. 抽象出共用的行为形成抽象类、父类

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

1. 设计可复用的类

1.1 LSP具体细则

父类能做的,子类一定能做

需要满足的条件有:

a) RI:相同或更强的不变量,子类RI>=父类RI

子类型:更弱的前置条件,更强的后置条件 (JAVA静态检测无法检测出来)

b)子类型可以增加方法,但不可删

c) 子类型需要实现抽象(父)类型中所有未实现方法

d) 子类型返回值类型与父类型返回值类型相同或是其子类型(更具体)

e) 子类型参数类型与父类型参数类型相同或是其父类型(更宽泛)

f) 子类型抛出的异常可以相同或是父类型抛出异常的子类型(更具体),不能抛出额外的异常

例题:

1. 前置更弱,后置更强

软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术

2. 当子类不满足父类方法时:

软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术

3. 子类父类RI不同时:

软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术
  1. 协变:

    子类重写父类方法后,返回值/抛出异常(或不抛出)类型更具体

    数组支持协变:子类可以赋值给父类,但不能直接赋值数字

  2. 反协变、逆变:

    子类重写父类方法后,传入参数类型更宽泛

    软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术
    注:JAVA不支持反协变,会将其当成重载overload而非override
  3. 通过协变进行方法调用
    1. 子类赋值给父类
      软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术
    2. 方法的参数是父类,调用时直接用子类调用
      软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术

2. 泛型相关的子类父类(*)

  1. 如果两个泛型之间存在subtyping关系,那么两个类的泛型是一模一样的。
    软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术
    例如:直接在编译阶段报错:
    软件构造复习 Chapter 44.1 可复用性的度量、形态与外部表现4.2 面向复用的软件构造技术
  2. 带?的泛型
    1. 使用object类型时
    2. 使用的方法和如List<?>的List类型无关
    3. 定下界写法<? superA>——存A或A的父类

      定上界写法:<? extends A>——存A或A的子类3.

3. 继承和委托