·复用有很多层次:代码层次(不推荐)、类的层次(推荐、默认)
·复用分为白盒复用和黑盒复用两类:
白盒复用:源代码可见,可修改和扩展,即继承。
黑盒复用:源代码不可见,不可修改,即通过类的接口调用类中方法。
·类的复用分为继承和委托两种方式:
继承就是子类继承父类的方法,可以重写,是典型的白盒复用。
委托又分为显式委托(明确的说明需要调用哪个类)和隐式委托(将调用这个操作封装在一个命令中,操作系统一般采用这种方式)。
·子类型多态:客户端可用统一的方式处理不同类型的对象。
B类继承了A类,说明B是A的子类型,A的对象集包含B,A中有的方法B中都有。
子类型可以增加方法,但不可删。
子类型需要实现抽象类型中所有未实现方法。
对于同一个方法,子类型中的规约应该比父类型具有更强的不变量、更弱的前置条件、更强的后置条件,即规约强度更高。
·LSP:
子类型对于父类型的RI可以修改,但修改针对的必须是在子类型中新定义的变量。
·Covariance(协变):子类型重写父类型中的方法时,返回值的类型可以变成父类型中该方法返回值类型的子类。
Contravariance(反协变/逆变):子类型重写父类型中的方法时,参数的类型可以变成父类型中该参数类型的父类。
注意,Java只支持协变,不支持逆变,它认为逆变不是重写而是重载。
·数组支持协变。例:声明一个Number类型的数组,一个Integer类型的数组,可以把Integer类型的数组赋值给Number类型的数组。
但是要注意,数组元素的类型取决于它存储的值的类型,不是数组的类型。
Java不支持泛型类之间的协变。
Object是所有类的父类。通配符<?>表示不确定;<? extends Object>表示有上界Object,只能是Object及它的子类;<? super Integer>表示有下界,只能是Integer及它的父类。。
·委托:有两种委托方式:①隐式委托:A类调用B类中的方法;②显式委托:A类中方法的参数表中包含B类对象。
·继承可以干的事,委托也能干。而委托能干的事,继承不一定能干。在使用的时候尽量多用委托少用继承。
·委托的形式:
①依赖Dependency:短时效性,通过传参实现委托。
②关联Association:长时效性,通过类型实现委托。
组合Composition:更强的association,但难以变化,通过在属性前加final
聚合Aggregation:更弱的association,松绑定,不加final,有方法改变属性值
·设计系统级复用:
白盒复用:遵守主控端的框架,重写其功能代码。使用继承。
黑盒复用:只需要对接口进行实现,看不见框架类。使用委托。