类和接口的设计,作者主要阐述了几个观点:
- 尽量多用接口,少用抽象类
- 将标签类抽取类层次,降低复杂度
- 如果一定是is-a的关系,采用继承,否则优先使用聚合
接口优于抽象类
java为了降低复杂度,减少菱形继承带来的危害,规范上只允许继承(extends)单个类,但是允许实现(implements)多个接口。
这意味着,如果要让一个类具备多种能力,实现接口是最佳的方式。
但是抽象类就一定不可取吗?也依情况而定。例如:
我们对一段数据进行分析,抽象了三个流程,分别是数据接收,数据处理以及数据输出。先确保这样一种抽象不会出错。对应接口定义如下:
public interface StreamParser {
void dataInput();
void dataProcess();
void dataOutput();
...可能还有些其他的流程
void parser();
}
这三个流程应该以一种pipeline的形式被使用,且流程不变,但是实现各有区别。好比,实时流,可能需要打开socket进行数据接收。而文件流,则可能是通过文件处理的相关工具直接read。但是实际的解析(parser)流程是不变的,那么就有必要提取一个公共的地方进行这个流程,也称骨架的定义。这正是模板方法的意义。
public abstract class AbstractStreamParser {
void parser() {
void dataInput();
void dataProcess();
void dataOutPut();
}
基于这个骨架,任何流的解析都只用实现各自的特殊逻辑。对于流程却不用关心。
java8
java8之后,引入了接口的默认实现,已经能够替代模板方法的场景。
但是默认方法无法完全覆盖抽象类的场景,主要在于当程序骨架比较复杂,依赖较多成员变量时,接口并不支持。