设计模式实战:享元模式(Flyweight)

在很多系统中,会存在这样的情况:

  • 对象数量非常多
  • 对象之间大量属性是相同的
  • 只有少量状态不同

如果每个对象都完整创建,就会导致:

  • 内存占用巨大
  • 对象创建成本高
  • 系统性能下降

这时候就可以使用 享元模式(Flyweight)


一、享元模式解决什么问题?

一句话:

通过共享对象,减少内存使用。

核心思想:

  • 把对象中可共享的部分提取出来
  • 多个对象共享同一份数据
  • 只把不同的部分作为外部状态

关键词:

  • 对象共享
  • 内存优化
  • 内部状态
  • 外部状态

二、一个典型场景:文本编辑器

假设一个文档有 100万字符

每个字符对象可能包含:

  • 字符内容
  • 字体
  • 字号
  • 颜色
  • 位置

如果每个字符都是完整对象:

复制代码
1000000 × 字体信息 × 样式信息

大量数据是重复的。

例如:

复制代码
字符: "A"
字体: Arial
字号: 12
颜色: 黑

可能出现几十万次。

这就是典型的享元模式使用场景。


三、享元模式的核心思想

享元模式会把对象状态拆成两部分:

1️⃣ 内部状态(Internal State)

可共享、不会变化。

例如:

  • 字符内容
  • 字体
  • 字号
  • 样式

这些可以被多个对象共享。


2️⃣ 外部状态(External State)

不可共享,每次不同。

例如:

  • 文档位置
  • 行号
  • 列号

这些由外部传入。


四、享元模式结构

典型结构:

复制代码
Flyweight
   |
ConcreteFlyweight
   |
FlyweightFactory

关键组件:

  • Flyweight:共享对象接口
  • ConcreteFlyweight:具体享元对象
  • FlyweightFactory:享元工厂(负责缓存)

五、Python 实现示例

我们实现一个"字符享元"。


1️⃣ 享元对象

python 复制代码
class CharacterFlyweight:

    def __init__(self, char, font, size):
        self.char = char
        self.font = font
        self.size = size

    def render(self, position):
        print(f"{self.char} ({self.font}, {self.size}) at {position}")

注意:

  • char/font/size → 内部状态
  • position → 外部状态

2️⃣ 享元工厂

python 复制代码
class FlyweightFactory:

    def __init__(self):
        self._cache = {}

    def get_character(self, char, font, size):
        key = (char, font, size)

        if key not in self._cache:
            self._cache[key] = CharacterFlyweight(char, font, size)

        return self._cache[key]

这里就是核心:

相同对象只创建一次。


3️⃣ 使用方式

python 复制代码
factory = FlyweightFactory()

c1 = factory.get_character("A", "Arial", 12)
c2 = factory.get_character("A", "Arial", 12)

c1.render(10)
c2.render(20)

注意:

复制代码
c1 is c2

这两个对象是 同一个实例


六、享元模式的关键:对象缓存

享元模式本质上是:

对象缓存 + 对象共享

最常见实现方式:

  • 字典缓存
  • 对象池
  • 单例对象集合

七、Python 中的"天然享元"

Python 其实已经在很多地方使用享元思想。

例如:

小整数缓存

python 复制代码
a = 10
b = 10

print(a is b)

结果:

复制代码
True

因为 Python 会缓存 -5 到 256 的整数


字符串驻留(String Interning)

python 复制代码
a = "hello"
b = "hello"

print(a is b)

很多情况下也是同一个对象。

这其实就是享元思想。


八、真实项目中的应用

享元模式非常适合:

1️⃣ 游戏开发

大量:

  • 子弹
  • 粒子
  • 树木
  • 草地

模型数据可以共享。


2️⃣ UI 系统

大量:

  • 图标
  • 字体
  • 样式

3️⃣ 缓存系统

例如:

  • 配置对象
  • 模板对象
  • 常用数据

4️⃣ ORM 框架

数据库字段、表结构元数据通常会共享。


九、享元模式优缺点

✅ 优点

  • 大幅减少内存使用
  • 减少对象创建成本
  • 提升系统性能

❌ 缺点

  • 系统结构变复杂
  • 外部状态管理困难
  • 不适合状态复杂对象

十、什么时候使用享元模式?

适合:

  • 大量对象
  • 对象大部分状态相同
  • 系统内存压力大

不适合:

  • 对象差异很大
  • 状态复杂
  • 对象数量不多

经验法则:

当对象数量达到几十万甚至百万级时,才值得考虑享元模式。


十一、一句话总结

享元模式的本质是:
共享不变数据,分离变化数据。

用一句更直白的话:

不要重复创建相同对象。

相关推荐
墨有6662 小时前
基于弦论流体对偶与环空间约化的湍流精确数值模型
python·流体力学·弦理论
兰文彬2 小时前
n8n 2.x版本没有内嵌Python环境
开发语言·python
smileNicky2 小时前
Spring AI系列之对话记忆与工具调用指南
人工智能·python·spring
飞Link2 小时前
深度解析 TS2Vec:时序表示学习中的层次化建模(Hierarchical Contrastive Learning)
开发语言·python·学习·数据挖掘
代码探秘者2 小时前
【Java集合】ArrayList :底层原理、数组互转与扩容计算
java·开发语言·jvm·数据库·后端·python·算法
格鸰爱童话3 小时前
向AI学习项目技能(二)
java·人工智能·python·学习
Sagittarius_A*3 小时前
傅里叶变换:从空域到频域的图像分析【计算机视觉】
图像处理·人工智能·python·opencv·计算机视觉·傅里叶变换·频域滤波
Pyeako3 小时前
深度学习--循环神经网络原理&局限&与LSTM解决方案
人工智能·python·rnn·深度学习·lstm·循环神经网络·遗忘门
困死,根本不会3 小时前
蓝桥杯python备赛笔记之(八)动态规划(DP)
笔记·python·学习·算法·蓝桥杯·动态规划