哈尔滨工业大学软件构造课程笔记第四章第二节

本文介绍了面向复用的软件构造技术,重点讨论了设计可重用的类,包括封装、继承、多态、行为分型和利斯科夫替代原理(LSP)。同时,讲解了授权和组成,以及如何设计系统级可重用库和框架,特别是API设计的重要性、框架设计的注意事项和Java集合框架的应用。
摘要由CSDN通过智能技术生成

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

1. 设计可重用的类

在OOP中设计可重用的类
▪封装和信息隐藏
▪继承与超越
▪多态、子类型和重载
▪泛型编程

▪行为分型和利斯科夫替代原理(LSP)
▪授权和组成

(1)行为分型和利斯科夫替代原理(LSP)

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

如果对于类型T的对象x,q(x) 成立,那么对于类型T的子类型S的对象y,q(y) 也成立。

Java中编译器强制的规则(静态类型检查)
子类型可以增加方法,但不可删
子类型需要实现抽象类型 (接口、抽象类)中所有未实现的方法
子类型中重写的方法必须有相同或子类型的返回值或者符合co-variant的参数
子类型中重写的
方法必须使用同样类型的参数或者符contra-variant的参数(此种情况Java目前按照重载overload处理)
子类型中重写的方法不能抛出额外的异常

也适用于指定的行为(方法):
更强的不变量
更弱的前置条件
更强的后置条件

利斯科夫替代原理(LSP)
LSP是子类型关系的一个特殊定义,称为
强行为子类型化

在编程语言中,LSP依赖于以下限制:
前置条件不能强化
后置条件不能弱化
不变量要保持
子类型方法参数:逆变
子类型方法的返回值:协变
异常类型:协变

协变
父类型→子类型:越来越具体specific
返回值类型:不变或变得更具体
异常的类型:也是如此。

class T {
   
  Object a() {
   }
}
class S extends T {
   
  @Override 
  String a() {
   } 
}
class T {
   
  void b( ) throws Throwable {
   }
}
class S extends T {
   
  @Override 
  void b( ) throws IOException {
   }
}
class U extends S {
   
  @Override 
  void b( ) {
   }
}

反协变、逆变
父类型→子类型:越来越具体specific
参数类型:要相反的变化,要不变或越来
越抽象

class T {
   
  void c( String s ) {
   }
}
class S extends T {
   
@Override 
  void c( Object s ) {
   } 
}

目前Java中遇到这种情况,当作overload看待

协变和逆变
Java中数组是协变的: 对T[]数组,可以保存类型T及其子类型的数据

泛型中的LSP
泛型是类型不变的
ArrayList是List的子类型
List不是List的子类型

类型参数在编译后被丢弃,在运行时不可用
这个过程称为类型擦除

泛型不是协变的。

可采用通配符实现两个泛型类的协变

** Class类型类**
Java在运行时,为所有对象维护一个运行时类型标识,这个标识跟踪对象所属的类,用来确定选择哪个方法运行。保存这些信息的类叫做“Class类型类”。注意:Class是类的名字,不是关键词class。每个”Class”的对象描述了一个类的信息

什么是类型擦除?
虚拟机中没有泛型类型对象-所有对象都属于普通类
泛型信息只存在于编译阶段,在运行时会被”擦除”
定义泛型类型时,会自动提供一个对应的原始类型(非泛型类型),原始类型的名字就是去掉类型参数后的泛型类型名。
擦除时类型变量会被擦除,替换为限定类型,如果没有限定类型则替换为Object类型。

运行时类型查询只适用于原始类型

泛型的通配符
无界通配符类型是使用通配符(?)指定的,例如List<?>。

有两种情况下,无界通配符是一种有用的方法:
-如果你正在写一个可以使用Object类中提供的功能来实现的方法。
-当代码使用泛型类中不依赖于类型参数的方法时。例如,列表。大小或List.clear。
-事实上,Class<?>之所以经常使用,是因为其中的大多数方法
类不依赖于T。

<? super A> 下限通配符

<? extends A> 上限通配符

(2)授权和组成

Comparator接口
这个接口对实现它的每个类的对象进行总体排序。
▪这种排序被称为类的自然排序,类的比较方法被称为类的自然比较方法。

另一种方法:让你的ADT实现Comparable接口,然后override compareTo() 方法

与使用Comparator的区别:不需要构建新的Comparator类,比较代
码放在ADT内部。

这不再是委托

委托
委派/委托:一个对象请求另一个对象的功能
委派是复用的一种常见形式
Sorter可以使用任意排序顺序重用
Comparators可以在需要比较整数的任意客户端代码中重用

可以将委托描述为在实体之间共享代码和数据的低级机制。
-显式委托:将发送对象传递给接收对象
-隐式委托:通过语言的成员查找规则

委托与继承
继承:通过新操作扩展基类或覆盖操作。
委托:捕捉一个操作并将其发送到另一个对象

很多设计模式将继承和委托结合使用

用委托代替继承
如果子类只需要复用父类中的一小部分方法
可以不需要使用继承,而是通过委派机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值