设计模式实战:享元模式(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 框架

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


九、享元模式优缺点

✅ 优点

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

❌ 缺点

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

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

适合:

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

不适合:

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

经验法则:

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


十一、一句话总结

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

用一句更直白的话:

不要重复创建相同对象。

相关推荐
周末也要写八哥13 小时前
返回函数(闭包):让return更“高阶
python
疯狂打码的少年13 小时前
【Day02 Java转Python】Python的ArrayList: list与tuple的“双面人生
java·python·list
暴力袋鼠哥13 小时前
基于 LightGBM 的山东高考智能择校推荐系统设计与实现
python·django·flask
5系暗夜孤魂14 小时前
当系统不再“透明”:从 Java 技术体系看大型工程的可观测性与可掌控性
java·python·压力测试
java1234_小锋14 小时前
Python高频面试题:python里面模块和包之间有什么区别?
开发语言·python
星马梦缘14 小时前
强化学习实战4——自定义环境的搭建
python·深度学习·机器学习·强化学习·q-learning·baseline3
青瓷程序设计14 小时前
基于YOLO的布匹缺陷检测系统~Python+目标检测+算法模型+2026原创
python·yolo·目标检测
276695829214 小时前
zp_stoken 算法风控分析
java·前端·javascript·python·web逆向·boss直聘·zp_stoken
生信研究猿14 小时前
leetcode 21.合并两个有序链表
python·leetcode·链表