组合优于继承是什么
优先用组合与委托获得复用:继承把子类绑死在父类的实现与接口上,父类改动可能波及所有子类;组合可以运行期替换实现,只暴露需要的能力。这条取向来自《设计模式》的总结,判断标准是语义——稳定的是一种关系用继承,以复用为目的、行为需要插拔时用组合。
基本信息
| 继承适合 | 是一种的语义稳定,契约可被完整继承 |
|---|---|
| 组合适合 | 行为需要插拔,以复用为主要目的 |
| 实现手段 | 委托加接口,必要时引入策略模式 |
| 判断信号 | 子类覆写了父类的大部分方法 |
| 代价对比 | 继承编译期绑定,组合可运行期替换 |
典型使用场景
- 需要按环境切换压缩、加密或存储实现
- 子类只用到父类的一小部分能力
- 继承层次超过两层并开始出现空实现
- 复用逻辑来自多个不相关的来源
- 要给已有类增加能力,但不想改动它所在的继承链
对照示例
对照示例
// 继承:压缩实现被绑死在父类上,换实现要改类型
// class StrongExporter extends Compressor { ... }
// 组合:只暴露需要的能力,实现可替换
class Exporter {
private final Compressor compressor;
Exporter(Compressor compressor) { this.compressor = compressor; }
byte[] export(Data data) { return compressor.compress(data); }
}继承与组合的选择
| 维度 | 继承 | 组合 |
|---|---|---|
| 关系语义 | 是一种 | 有一个 |
| 绑定时机 | 编译期确定 | 运行期可替换 |
| 暴露程度 | 父类接口全部继承 | 只暴露需要的方法 |
| 变化影响 | 父类改动波及子类 | 实现替换互不影响 |
判断信号很实用:如果子类覆写了父类大多数方法,或层次里出现大量空实现,说明继承被当作复用手段而不是关系表达,应该改成组合。
用组合却把被委托对象的全部接口原样暴露,等于换了一层皮的继承:调用方仍与具体实现强耦合,替换实现时照样要改所有调用点。