接口、抽象 class 和实现
Interface, abstract class, and the implementation
在 java 中,我经常发现自己实现了 List
接口,而不是例如扩展 AbstractList
class。这在 Java API(以及我看过的许多第三方库)中很常见,存在一个接口和该接口的抽象 class。
这是为什么?为什么对于一个接口存在一个抽象 class 为其提供一些默认行为如此普遍?是否有充分的理由不像这样调用抽象 class,比如 DefaultListImpl
等?
有趣的问题,我想很多人会有很多意见。从我的角度来看:
- 创建了接口来描述合约,应该没有任何实现
- 这在 Java 8
中使用默认方法进行了更改
- 接口在 Java 生态系统中具有特殊的地位
- 例如
java.lang.reflect.Proxy
只支持接口代理,不支持抽象类
- 很多mocking框架不支持类的mocking,只支持接口的mocking
- 即使这条规则有例外
所以总是有使用接口的理由。这些问题将非常类似于 abstract 类 vs. Scala 中的 traits。
你提出的命名约定DefaultListImpl
不是一个好主意:
Default
没有说明任何实现,如果我们不能正确命名,我们要么:
- 不完全理解我们正在实施的内容,
- 或者想不出多个实现,这可能是过于复杂的标志API
Impl
会产生误导,因为许多人会期望完全实现功能
在 java 中,我经常发现自己实现了 List
接口,而不是例如扩展 AbstractList
class。这在 Java API(以及我看过的许多第三方库)中很常见,存在一个接口和该接口的抽象 class。
这是为什么?为什么对于一个接口存在一个抽象 class 为其提供一些默认行为如此普遍?是否有充分的理由不像这样调用抽象 class,比如 DefaultListImpl
等?
有趣的问题,我想很多人会有很多意见。从我的角度来看:
- 创建了接口来描述合约,应该没有任何实现
- 这在 Java 8 中使用默认方法进行了更改
- 接口在 Java 生态系统中具有特殊的地位
- 例如
java.lang.reflect.Proxy
只支持接口代理,不支持抽象类
- 例如
- 很多mocking框架不支持类的mocking,只支持接口的mocking
- 即使这条规则有例外
所以总是有使用接口的理由。这些问题将非常类似于 abstract 类 vs. Scala 中的 traits。
你提出的命名约定DefaultListImpl
不是一个好主意:
Default
没有说明任何实现,如果我们不能正确命名,我们要么:- 不完全理解我们正在实施的内容,
- 或者想不出多个实现,这可能是过于复杂的标志API
Impl
会产生误导,因为许多人会期望完全实现功能