原型对象是享元模式的高效执行底座而非模式本身,它通过方法共享和object.create支持内部状态复用与外部状态注入,但需工厂管控和状态分离设计才能构成完整享元模式。

原型对象本身不是享元模式的实现载体,但它能天然支撑享元模式的关键机制——对象复用与状态分离。享元模式的核心不在“原型链”上,而在“共享实例 + 外部状态注入”的结构设计中;而 JavaScript 的原型机制,恰好为这种结构提供了轻量、高效、无需额外继承语法的底层支持。
原型对象如何辅助享元对象复用
享元工厂返回的通常是普通对象或类实例,这些实例的通用方法(如 draw、render、update)完全可以定义在原型上,而非每个实例重复挂载:
- 避免在每次创建享元时重复分配方法函数,节省内存
- 所有享元实例共享同一份方法逻辑,符合“内部状态可共享”的原则
- 方法中只操作传入的外部参数(如坐标、尺寸、ID),不依赖实例自身存储的状态
例如,一个字符享元可这样组织:
function CharFlyweight(font, size, color) {
this.font = font;
this.size = size;
this.color = color;
}
CharFlyweight.prototype.draw = function(x, y, bold) {
console.log(`Render "${this.char || '?'}" at (${x},${y}) with ${this.font}, ${this.size}px, ${this.color}, bold=${bold}`);
};
这里 font/size/color 是内部状态(构造时固化、可共享),x/y/bold 是外部状态(调用时传入、不可共享)。方法放在原型上,1000 个享元共用同一个 draw 函数,而不是各自拷贝一份。
用 Object.create 直接基于原型构建享元
不依赖 new 和构造函数,也可用 Object.create 显式指定原型,快速生成享元实例:
- 定义一个基础享元原型对象,含所有共享行为和默认内部状态
- 工厂根据内部状态键(如 "Arial-12-black")查找或创建对应原型
- 调用 Object.create(proto) 得到新实例,再注入唯一外部状态(如位置、ID)
这种方式更贴近原型本质,也更轻量——没有构造函数开销,也没有 this 绑定歧义。
享元工厂与原型协同管理共享池
享元工厂负责缓存和复用,而原型负责统一行为。二者分工明确:
- 工厂用对象字面量或 Map 存储已创建的享元原型(按内部状态哈希键索引)
- 每个缓存项是一个完整享元对象,其 __proto__ 指向公共行为原型
- 客户端获取享元后,仅需设置/传入外部状态,不修改享元自身内部属性
例如:多个红色圆形享元共用同一个 CircleRedPrototype,它们的 radius、strokeWidth 等可变参数由调用方传入,不写入实例。
注意原型与享元的边界
原型机制不能替代享元模式的逻辑设计:
- 原型链解决的是方法复用,不是状态共享策略
- 若把外部状态(如位置、ID)也塞进原型,会导致所有实例互相污染
- 真正的享元效果来自“一个享元实例服务多个上下文”,这必须靠工厂控制+调用约定来保障
换句话说:原型是享元模式的**高效执行底座**,不是它的**模式定义本身**。离开状态分离和工厂管控,单靠原型无法构成享元模式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











