组合模式通过将行为拆分为可插拔组件并由对象持有来替代复杂继承树,提升灵活性、可测试性及对JS原型特性的契合度。

JavaScript 中用组合模式替代复杂继承树,核心思路是“把行为拆成可插拔的部件,让对象通过持有这些部件来获得能力”,而不是靠层层继承去堆积功能。这更灵活、更易测试、也更符合 JavaScript 的原型和对象特性。
用对象组合代替类继承
继承树容易导致类职责过重、耦合高、难以复用。组合模式则让每个功能模块独立存在,比如 Renderer、Physics、InputHandler 都是普通对象,不依赖继承关系:
- 创建一个基础实体对象(如
GameObject),它只负责管理组件列表和生命周期 - 每个组件是一个纯函数或轻量类,只专注一件事(例如
SpriteRenderer.update()只处理绘制,RigidBody.update()只处理位移和碰撞) - 实体通过
addComponent(renderer)和getComponent(Renderer)动态装配能力
手动实现一个轻量组合系统
不需要框架也能快速搭出组合逻辑。关键在于统一的组件注册、查找与更新机制:
- 每个组件带唯一类型标识(如
component.type = 'renderer'或用构造函数作为 key) - 实体内部用
Map或普通对象缓存组件:this.components.set(Renderer, renderer) - 在主循环中遍历所有实体,再对每个实体调用其各组件的
update(dt)、render(ctx)等方法 - 组件之间通信不走继承链,而是通过事件(
entity.emit('damage', amount))或直接传参(health.takeDamage(amount))
避免“伪组合”陷阱
有些写法看似用了组合,实则还是继承思维残留:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 不要让组件继承自某个“BaseComponent”类——除非真有通用生命周期钩子,否则用 mixin 或纯函数更轻量
- 别把组件设计成必须挂载到特定父类上(如强制要求
this.entity存在),应支持独立运行或被多个上下文复用 - 避免组件之间强依赖(如 A 组件硬编码调用 B 组件的方法),改用接口约定(
if (entity.has('health')) entity.get('health').heal(10))或事件解耦
配合现代 JS 特性更自然
利用 ES6+ 语法可让组合更简洁直观:
- 用 私有字段(
#components = new Map())封装内部状态 - 用 静态属性定义组件类型:
Renderer.type = 'renderer',便于查找和调试 - 用 可选链(
entity.getComponent(Animator)?.play('run'))安全调用可能不存在的组件 - 搭配 工厂函数快速生成预设组合:
createPlayer() { return new GameObject().add(new SpriteRenderer()).add(new RigidBody()) }
组合不是彻底否定继承,而是把继承留给真正共享的底层协议(比如所有组件都有 init() 和 destroy()),其余业务逻辑交给组合驱动。这样结构扁平、扩展性强,改一个功能不影响其他模块,也更容易做热替换和运行时配置。

















