1.可复用性的概念
复用的类型
软件复用:最主要的是代码复用,但也有其他方面。
Source code level:methods, statements, etc Module level:class and interface Library level:API Architecture level:framework
白盒复用:源代码可见、可修改和扩展(对应继承)
黑盒复用:源代码不可见,不能修改,只能通过API接口使用(对应委托)
代码复用
即直接复制代码(不推荐)
类的复用
inheritance 继承 delegation 委托
继承能做的事委托也能做,继承要求严格父子关系
框架(framework)
框架:一组具体类、抽象类、及其之间的连接关系
开发者根据framework的规约,填充自己的代码进去,形成完整系统
API和框架的区别:主控端在用户/框架
programming for reuse 面向复用编程:开发出可复用的软件
programming with reuse 基于复用编程:利用已有的可复用软件搭建应用系统
- 优点
- 降低成本和开发时间
- 经过充分的测试,可靠、稳定
- 标准化,在不同应用中保持一致
2. 面向复用的软件构造技术
Liskov Substitution Principle 里氏替换原则(LSP)
- 子类型多态:客户端可用统一的方式处理不同类型的对象
- 在可以使用父类的场景,都可以用子类型代替而不会有任何问题
- 编译强制规则
- 子类型可以增加方法,但不可删除方法
- 子类型需要实现抽象类型中的所有未实现方法
- 协变:子类型中重写的方法必须有相同或子类型的返回值或者符合co-variance的参数
- 逆变:子类型中重写的方法必须使用同样类型的参数或者符合contra-variance的参数
- 子类型中重写的方法不能抛出额外的异常
- Also applies to specified behavior (methods):
- Same or stronger invariants 更强的不变量
- Same or weaker preconditions 更弱的前置条件
- Same or stronger postconditions 更强的后置条件
协变 & 反协变
父类型 → 子类型:
- 协变:返回值和异常不变或越来越具体
- 逆变(反协变):参数类型要相反地变化,要不变或越来越抽象
注意:Java不支持反协变!Java识别其为重载(而非重写)
数组满足协变。
泛型不满足协变 List<String>
不是List<Object>
的子类型
Object是所有泛型的父类,List<?>
是List<Object>
的父类
这是因为发生了类型擦除,运行时就不存在泛型了,所有的泛型都被替换为具体的类型。
但是在实际使用的过程中是存在能够处理不同的类型的泛型的需求的,如定义一个方法参数是List<E>
类型的,但是要适应不同的类型的E,于是可使用通配符?
来解决这个需求:
- 无类型条件限制:
-
public static void printList(List<?> list) { for (Object elem: list) System.out.print(elem + " "); }
- 当为A类型的父类型
public static void printList(List<? super A> list){...}
- 当为A类型的子类型
public static void printList(List<? extends A> list){...}
委托(Delegation)
Interface Comparator< T >
int compare(T o1, T o2): Compares its two arguments for order
如果你的ADT需要比较大小,或者要放入Collections或Arrays进行排序,可以实现Comparator接口并且override compare()函数
另一种方法:让ADT实现Comparable接口,然后override compareTo() 方法
与使用Comparator的区别:不需要构建新的Comparator类,比较代码放在ADT内部
- 一个对象请求另一个对象的功能
- 通过运行时动态绑定,实现对其他类中代码的动态复用
- 如果子类只需要复用父类中的一小部分方法,可以通过委托机制调用。
- 委托是复用的一种常用形式。(CRP原则:尽量使用委托进行复用)
- Use 使用:通过方法的参数传递(use_a)
- Association 关联:通过类的属性传递(has_a)
- “委托”发生在object层面
- “继承”发生在class层面
composition/aggregation 组合/聚合(可认为是Association的两种具体形态)
聚合运行时可更改绑定对象(较弱的关联)
聚合B类销毁时,A类可能不会销毁(可能还有指向其的指针);组合B类销毁时,A类同时被销毁
白盒框架 & 黑盒框架的原理与实现
- 黑盒框架
- 通过实现特定接口进行框架扩展,采用的是delegation机制达到这种目的,通常采用的设计模式是策略模式(Strategy)和观察者模式(Observer);
- 黑盒所预留的是一个接口,在框架中只调用接口中的方法,而接口中方法的实现就依据派生出的子类型的不同而不同,它的客户端启动的就是框架本身。
- 白盒框架
- 通过继承和重写实现功能的扩展,通常的设计模式是模板模式(Template Method);
- 白盒框架所执行的是框架所写好的代码,只有通过override其方法来实现新的功能,客户端启动的的是第三方开发者派生的子类型。