组合模式是重构复杂继承关系的视角,通过提取日志、校验等共用能力为独立组件,以构造注入接口实现解耦、动态替换与嵌套策略,同时明确组合/聚合生命周期及避免循环引用。

组合模式不是用来“替换继承”的工具,而是帮你重新思考对象关系的视角。当继承结构变得复杂、难维护、一改就崩时,说明你正在用“is-a”强行表达“has-a”,这时候该转向组合。
识别可拆解的行为边界
先看现有继承链里哪些功能是真正共用的,且不随具体类型变化。比如多个类都需要日志、校验、重试或序列化——这些都不是类本身的身份,而是它“拥有的能力”。把它们一个个拎出来,各自封装成小而专的类:
- Logger 接口 + ConsoleLogger、FileLogger、MockLogger 实现
- Validator 接口 + EmailValidator、LengthValidator 实现
- RetryPolicy 类只管重试逻辑,不耦合网络或业务
每个组件只做一件事,接口最小化,避免“全能工具类”。
用构造注入代替 extends
原来写 class OrderService extends BaseService,现在改为 class OrderService,内部声明依赖字段:
- 通过构造函数传入 logger、validator、paymentStrategy 等实例
- 依赖类型用接口(如 Logger),而非具体类(如 FileLogger)
- 可选组件用 Optional 或可空类型包装,不强制初始化
这样测试时直接传 Mock 对象,上线时换实现类,无需动主逻辑。
支持运行时嵌套与动态切换
组合天然支持嵌套和策略切换,不像继承在编译期就锁死:
- 一个 OrderProcessor 可持有 PaymentStrategy、NotificationStrategy、CacheStrategy 多个组件
- 下单时根据用户地区选支付方式:strategyFactory.getStrategy(country)
- 需要叠加多种通知?用 CompositeNotifier 聚合 EmailNotifier + SmsNotifier,自身不继承任何 notifier
嵌套层级不宜过深(如 A→B→C→D),若出现长委托链,考虑合并相邻组件,或引入事件总线解耦。
明确生命周期与所有权关系
组合不是随便 new 一堆对象塞进类里。要区分:
- 组合(Composition):生命周期一致,如订单包含订单项,删订单即清空所有项 → 在构造函数中创建
- 聚合(Aggregation):生命周期独立,如用户持有邮箱服务,换服务商不影响用户 → 由外部容器注入或工厂获取
- 避免循环引用:A 持有 B,B 又持有 A,会导致初始化失败或内存泄漏
资源型对象(DB 连接、HTTP 客户端)统一交由 DI 容器管理,业务类不自行 new。










