← 返回题目列表

享元模式适合哪些应用场景?

高频 中等 第 10 / 25 题 更新于 2026/07/28
享元模式应用场景内存优化

简化版

享元模式适合大量对象具有重复状态、并且重复状态可以共享的场景。常见应用包括文本编辑器字符对象、游戏地图元素、围棋棋子、图标和字体样式、连接或对象池、权限或配置模板等。

详细版

享元模式适用场景通常具备几个特征:

  • 对象数量非常大。
  • 对象创建和内存占用成为问题。
  • 对象中有可重复、可抽离的内部状态。
  • 外部状态可以由客户端维护。

典型例子:

  • 文本编辑器中大量字符共享字体样式。
  • 游戏中大量树木、子弹、粒子共享模型和贴图。
  • 棋盘游戏中黑白棋子共享颜色和渲染样式。
  • 图标系统中共享同一类图标元数据。
  • 业务系统中共享只读配置、规则模板、权限模板。

完整版教学

一、文本编辑器字符和样式

文本编辑器可能有成千上万个字符。如果每个字符对象都保存完整字体、字号、颜色、样式,会产生大量重复。

可以把字体样式做成享元:

  • 内部状态:字体名、字号、颜色、粗体等。
  • 外部状态:字符内容、行列位置、选中状态。

多个字符可以共享同一个字体样式对象。

二、游戏地图和渲染对象

游戏地图上经常有大量重复元素:

  • 树木。
  • 草丛。
  • 石头。
  • 子弹。
  • 粒子。

这些对象的模型、贴图、基础颜色可能相同,坐标、速度、生命值不同。

享元模式可以共享模型和贴图,把坐标等变化信息放在实例数据中。这样既减少内存,也减少资源加载次数。

三、棋类游戏中的棋子

围棋、五子棋、象棋都可以用享元思想。

例如围棋棋子只有黑白两种颜色。棋盘上每一步落子位置不同,但棋子颜色和渲染样式可以共享。

这种例子适合说明内部状态和外部状态的区别。

四、图标、字体和样式库

前端或桌面应用中,大量组件可能使用相同图标、字体、颜色配置。

这些资源对象可以集中管理:

  • 图标元数据共享。
  • 字体对象共享。
  • 主题样式共享。

如果每个组件都复制一份资源描述,会造成浪费,也让更新难以统一。

五、只读模板和规则配置

业务系统中也有享元场景。例如:

  • 通知模板。
  • 权限模板。
  • 风控规则模板。
  • 报表字段配置。

这些模板通常是只读的,可以被多个用户、订单或请求共享。请求中的用户 ID、订单 ID、上下文参数属于外部状态。

六、对象池是否一定是享元

连接池、线程池、对象池经常和享元一起被提到,但它们不完全一样。

对象池主要复用昂贵对象,关注创建和销毁成本;享元主要共享内部状态,关注大量细粒度对象的内存占用。

如果对象池中的对象有独立生命周期和可变状态,就不能简单叫享元。它们只是都体现了复用思想。

七、不适合使用的场景

不适合享元的情况包括:

  • 对象数量不多。
  • 对象之间没有明显重复状态。
  • 对象大部分状态都依赖上下文。
  • 共享对象需要频繁修改。
  • 缓存 key 种类无限增长。

这些情况下,引入享元可能得不偿失。

八、常见误区与追问

适用场景必须同时满足对象多、内部状态重复、外部状态可拆。地图上有100000棵树但纹理只有8种,字形布局有百万字符但字体组合有限,都是典型候选;若每个对象纹理都不同,K 接近 N,共享收益迅速消失。数据库连接池虽复用对象,但主要解决昂贵资源生命周期,不属于典型状态拆分享元。

检查维度判定依据
高匹配N 大、K 小、内部状态重且不可变
低匹配状态高度唯一或必须频繁修改
适合度 ∝ 对象数 × 重复率 × 内部状态大小

心法:先看堆里是不是有“大量长得一样的重对象”。

  • 误区:对象池都属于享元模式。 对象池通常借出可变资源并归还,享元允许并发共享不可变状态。
  • 追问:游戏粒子为何常用享元? 纹理和模型可共享,位置、速度和寿命由每个粒子保存。
  • 误区:缓存查询结果天然适合享元。 结果缓存不一定拆分内外状态,其目标和失效语义也不同。
  • 追问:如何发现候选对象? 堆转储中查看数量大、浅大小相似且字段高度重复的类型。
  • 追问:什么时候应放弃? 共享键高基数、状态可变或外部参数使 API 难以维护时。

九、加强记忆

享元模式适合“数量多、重复多、可共享、可拆状态”的场景。只要对象的大部分差异来自外部上下文,而核心类型信息可以复用,就可以考虑享元。