1、什么是设计继承并提供文档
对于需要被继承的类而言,我们要进行专门设计,并且提供文档说明。
2、为什么要设计继承并提供文档否则禁止继承
Effective Java代码规则之十八条规则提醒过我们继承的危害性,如果不好好设计可继承类并且提供文档说明,我们就应该禁止该类被继承。
3、如何设计继承并提供文档
3.1、设计继承类的约束
- 类必须通过某种形式提供适当的钩子
类必须以精心挑选的受保护的(protected)方法的形式,提供适当的钩子( hook ),以便进入其内部工作中。例如,以java.util.AbstractList中的removeRange方法为例:
protected void removeRange(int fromIndex, int toIndex) { ListIterator<E> it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; i<n; i++) { it.next(); it.remove(); } }
提供该方法的唯一目的在于,使子类更易于提供针对子列表( sublist )的快速clear方法。如果没有removeRange方法,当在子列表( sublist )上调用clear方法时,子类将不得不用平方级的时间来完成它的工作。否则,就得重新编写整个subList机制。
- 必须在发布类之前先编写子类对类进行测试
- 构造器决不能调用可被覆盖的方法
超类的构造器在子类的构造器之前运行,所以,子类中覆盖版本的方法将会在子类的构造器运行之前就先被调用 。如果该覆盖版本的方法依赖于子类构造器所执行的任何初始化工作,该方法将不会如预期般的执行。
- 对于实现了Cloneable接口的类,在clone方法中不能调用可被覆盖的方法
对于clone方法,覆盖的方法则是在子类的clone方法有机会修正被克隆对象的状态之前先被运行。
- 对于实现了Serializable接口的类,在readObject方法中不能调用可被覆盖的方法
对于readObject方法,覆盖的方法将在子类的状态被反序列化(deserialized)之前先被运行。
- 对于实现了Serializable接口的类,readResolve和writeReplace方法必须是protected的
如果这些方法是私有的,那么子类将会不声不响地忽略掉这两个方法。
3.2、如何提供文档说明
- 该类的文档必须精确地描述覆盖每个方法所带来的影响
- 对于可覆盖的方法,它的文档中要说明它们调用了自己的哪些public或protected类型的方法(非final),并说明调用顺序和每次调用的作用
- 文档编写完成,并发布新版本之后,后续的版本不能违背文档中的细节
4、如何禁止继承
- 把这个类声明为final的
- 将类的构造器申明为私有或包级私有类型,然后用静态工厂获取实例
5、最佳实践
在实际工作中,专门为了继承而设计类并且建立文档说明是一件很辛苦的工作,我们应该尽量使用复合来代替继承。
#IT极客老兵#