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

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


九、享元模式优缺点

✅ 优点

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

❌ 缺点

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

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

适合:

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

不适合:

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

经验法则:

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


十一、一句话总结

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

用一句更直白的话:

不要重复创建相同对象。

相关推荐
happylifetree13 小时前
Python67:核心语法-函数进阶-参数类型(函数作为参数)
python
小羊没烦恼!13 小时前
铁道部新客票系统设计(二)
开发语言·前端·数据库·python·oracle·c#·php
quantdash_cc14 小时前
从实时行情到价格观察表:用 Python 和 Pandas 构建策略输入数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
镜子AI14 小时前
镜子AI工程实践:用 Python 做 GEO 实体一致性审计,并自动生成 JSON-LD 结构化数据
人工智能·python·json
MobotStone17 小时前
AI 写代码越来越爽,但程序员可能越来越废了
人工智能·设计模式
2601_9628857218 小时前
如何用 Python 计算 VaR 和 CVaR(在险价值)?
开发语言·python
李航198318 小时前
DeepSeekAI建模三 - 实战建模一组柜子
人工智能·python·计算机视觉·ai·ai编程
墨子夕19 小时前
设计模式——Java × Python 双语言精讲 · 23 个经典模式 + 现代演进(前言篇)
java·开发语言·设计模式
严谨的麻辣烫19 小时前
静态代理 IP 的出口一致性如何验证?Python 请求检测与异常排查
开发语言·python·http·网络安全
我命由我1234520 小时前
5-1.Python 编码进阶 - 函数进阶(参数、返回值、递归、函数作为参数传递、lambda 匿名函数)
java·服务器·数据库·后端·python·java-ee·python3.11