组合模式通过“has-a”替代“is-a”关系,用实例持有能力模块实现功能拼装;定义统一组件接口(render/update/destroy),区分叶节点与组合节点;能力模块可插拔、独立测试,支持配置驱动组装,提升复用性与可维护性。

用组合模式代替复杂继承,核心是把“是什么”(is-a)关系,转成“有什么”(has-a)关系。不靠层层 extends,而是让对象持有其他能力模块的实例,按需拼装功能。结构更扁平、逻辑更可控、测试和复用也更直接。
明确组件边界,定义统一接口
先抽象出一个基础组件类,只声明通用行为,比如 render、update、destroy,不实现具体逻辑。所有真实组件——无论是按钮、表单还是图表——都实现这个接口。这样客户端调用时不用区分它是单个对象还是组合体,统一处理:
- 叶节点(Leaf):如
TextInput,自己完成渲染,不管理子项 - 组合节点(Composite):如
Form,内部持有一组TextInput、SubmitButton实例,render()时遍历调用每个子项的render()
用实例持有替代原型继承
与其让 ChartWithExport 继承 ChartWithLoading 再继承 BaseChart,不如让它在构造时接收所需能力:
new Chart({ renderer: new CanvasRenderer(), exporter: new PdfExporter(), loader: new DataLoader() })- 所有能力模块独立开发、单独测试,
Chart只负责协调,不耦合实现细节 - 切换导出方式只需换一个
exporter实例,无需改类结构或重写方法
封装常用能力为可插拔模块
把横切关注点(如日志、事件、校验)抽成小而专的类,通过组合注入:
class UserForm { constructor(logger, validator) { this.logger = logger; this.validator = validator; } }- 避免混入(Mixin)带来的命名冲突和调试模糊,每个能力有明确归属和生命周期
- 团队协作时,新增校验规则只需更新
validator类,不影响UserForm主逻辑
配合工厂或配置驱动组装逻辑
当组合变多,可用工厂函数或配置对象统一初始化:
createReportWidget({ dataSource: 'api', format: 'pdf', theme: 'dark' })- 工厂内部决定注入
ApiDataSource、PdfExporter、DarkTheme等实例 - 业务侧只关心“要什么效果”,技术侧控制“怎么拼出来”,职责分离更清晰
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











