跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

组合Composition与继承Inheritance在代码复用选型

优先选组合而非继承,因组合更灵活、可测试性好、语义清晰;继承仅适用于满足“is-a”关系且父类明确为继承设计的情形,如AbstractList;误用如Dog extends DatabaseConnection违背语义,属典型坏味道。 优先选组合,慎用继承。继承容易导致紧耦合、破坏封装,而组合更灵活、可测试性更好、语义更清晰。 什么时候该用继承 仅当满足“ is-a ”关系,且父类是为继承而设计的(比如明确标注了
protected
接口、有文档说明可被子类重写、提供
template method
等钩子)。 Java 的
AbstractList
是为继承设计的,可以安全扩展 但
ArrayList
不是——它没承诺任何继承契约,直接继承它属于误用 如果只是想复用逻辑,却强行让
Dog extends DatabaseConnection
,就违背了语义,是典型坏味道 组合怎么写才真正有效 组合不是简单地在类里 new 一个对象,关键在于:通过接口依赖、控制生命周期、暴露必要能力。 依赖抽象而非具体类型:用
PaymentProcessor
接口,而不是
PayPalProcessor
类 外部可替换:测试时能轻松注入 mock,生产时可切换 Stripe 实现 不暴露内部细节:比如
OrderService
持有
NotificationSender
,但不把 sender 的 connect() 或 retry() 方法透给上层调用 继承的常见陷阱 看似省代码,实则埋雷: 脆弱基类问题 :父类一改,所有子类行为可能意外变化(比如加了个新 protected 方法,恰好和子类同名,引发覆盖或编译错误) 构造顺序陷阱 :子类构造器中调用被重写的方法,此时父类字段还没初始化完毕,易出 NullPointerException 无法多重复用 :Java 不支持多继承,而一个类常需多种能力(如可缓存 + 可重试 + 可熔断),组合天然支持横向叠加 一个实用判断流程 遇到复用需求时,快速自问三句: 它真的是“是一种”关系吗?( 不是“有一个”或“用一下” ) 父类是否公开声明支持继承?有没有配套的 hook 和文档? 如果明天要换掉这个能力(比如短信通知换成邮件),继承方案要改几处?组合方案改几处? 多数时候,第三问的答案会告诉你:组合更轻、更稳、更可持续。

相关文章