📋 Research Summary
享元模式是处理"海量细粒度对象"内存问题的经典方案。在文本编辑器(字符共享)、游戏引擎(粒子系统、树木渲染)中广泛应用。Java 的 String.intern()、Python 的小整数缓存都是其体现。
🌱 逻辑原点
如果游戏需要渲染 100 万棵树,每棵树都有位置、大小、纹理等属性,但树的种类只有 5 种,你真的需要创建 100 万个对象吗?
对象数量与内存容量的矛盾:实例数量巨大,但大部分状态是重复且不变的。

🧠 苏格拉底式对话
1️⃣ 现状:最原始的解法是什么?
为每个对象创建独立实例:
python
class Tree:
def __init__(self, x, y, name, color, texture):
self.x = x # 外部状态:每个树不同
self.y = y # 外部状态
self.name = name # 内部状态:大量重复
self.color = color # 内部状态
self.texture = texture # 内部状态(可能占用大量内存)
# 100 万棵树
forest = [Tree(x, y, "Oak", "Green", oak_texture) for x, y in positions]
优点 :简单直接,每个对象独立。
问题:内存占用巨大,大量重复数据。
2️⃣ 瓶颈:规模扩大 100 倍时会在哪里崩溃?
当需要渲染 1000 万棵树时:
- 内存爆炸:每棵树的纹理数据 10MB,1000 万棵需要 100TB 内存!
- GC 压力:大量对象导致垃圾回收频繁,程序卡顿
- 缓存失效:CPU 缓存无法容纳这么多对象,频繁访问主存
- 启动时间:加载所有纹理需要数小时
核心矛盾:我们需要 1000 万个"标识"(每棵树的位置不同),但只需要 5 个"类型"(树的种类)。
3️⃣ 突破:必须引入什么新维度?
分离内部状态与外部状态。
不是"每棵树都是独立对象",而是"共享内部状态,传递外部状态"。内部状态(树的种类、纹理)只有 5 份,外部状态(位置)在使用时传入:
享元工厂:管理 5 个 TreeType 对象(共享)
上下文:包含 x, y 和 TreeType 引用(轻量)
渲染时:TreeType.draw(x, y) -- 传入外部状态
这就是享元的本质:将对象状态分类,共享不变的部分,传递变化的部分。
📊 视觉骨架
请求树 request tree
返回享元 return flyweight
缓存 cache
创建上下文 create context
引用 reference
包含 contain
客户端 Client
享元工厂 Flyweight Factory
树类型 TreeType
享元池 Pool
树上下文 Tree Context
外部状态 External State x,y
关键洞察:享元模式将对象分为"享元对象"(共享的内部状态)和"上下文"(独有的外部状态)。1000 万个上下文对象都很小(只包含坐标和引用),只有 5 个享元对象包含大纹理数据。
⚖️ 权衡模型
公式:
Flyweight = 解决了海量对象的内存问题 + 牺牲了运行时性能 + 增加了状态管理复杂度
代价分析:
- ✅ 解决: 大幅减少内存占用、减少对象创建开销、提高缓存命中率
- ❌ 牺牲: 运行时性能(需要传入外部状态)、代码复杂度(需要区分内外状态)
- ⚠️ 增加: 状态管理复杂度(外部状态需要由客户端维护或计算)、线程安全问题(共享对象的并发访问)
使用建议:当系统需要创建大量相似对象,且内存是瓶颈时使用。关键是识别出可以共享的内部状态。适合场景:字符渲染、游戏粒子、地图标注、连接池。
🔁 记忆锚点
python
class TreeType:
"""
享元对象:共享的内部状态
"""
def __init__(self, name: str, texture: bytes):
self.name = name
self.texture = texture # 大量数据,只存一份
def draw(self, x: int, y: int) -> None:
"""外部状态由调用方传入"""
render(self.texture, x, y)
class TreeFactory:
"""
享元工厂:管理共享对象
"""
_tree_types: Dict[str, TreeType] = {}
@classmethod
def get_tree_type(cls, name: str, texture: bytes) -> TreeType:
"""获取或创建享元对象"""
if name not in cls._tree_types:
cls._tree_types[name] = TreeType(name, texture)
return cls._tree_types[name]
class Tree:
"""
上下文:轻量级对象
"""
def __init__(self, x: int, y: int, tree_type: TreeType):
self.x = x # 外部状态
self.y = y # 外部状态
self._type = tree_type # 引用享元对象
def draw(self) -> None:
"""渲染时传入外部状态"""
self._type.draw(self.x, self.y)
一句话本质: 享元模式 = 共享内部状态,传递外部状态,用计算换内存。