← 每日面试题 学习看板

什么是享元模式,有哪些具体应用?

面试题/02架构设计题/09设计模式/什么是享元模式,有哪些具体应用?.md

面试记录 2026-10-09

题目:什么是享元模式,有哪些具体应用?

难度:low

标签:arch/design-pattern, architecture/design, general/knowledge

评分:⭐⭐☆☆☆(2/5)

我的回答

享元模式。享元模式其实有点类似于单例模式,但是它是单例模式的一个延伸,相当于把单例模式的单个对象进行了类似于池化的操作,进行重复使用。比如 Spring 中对对象的管理,统一进行对象的统一管理,然后分配处理,其实就是一种享元模式的延伸使用。还有还有 Java 中 String 的,把 String 的那个元空间,把 String 对象,字符串对象进行持久化,然后不是反复的创建相同的字符串,这种都是享元模式的使用。

点评

优点:

不足:

补充(享元模式完整知识):

完整讲解

第一部分:知识重点剖析

核心考点定位:验证对享元模式本质的理解——用"不可变共享对象"换内存,以及能否准确识别 JDK 中的享元应用。

知识点拆解:

  1. 底层原理:享元模式(Flyweight Pattern)是 GoF 创建型设计模式之一,通过把对象拆成"内蕴状态(intrinsic state,可共享的不变量)"和"外蕴状态(extrinsic state,调用者自己持有)",让多个对象共享同一份内蕴状态,减少对象总数、节省内存。共享的前提是内蕴状态必须不可变(immutable)。
  2. 经典应用:
  1. 设计权衡:享元用运行时共享逻辑换取了内存效率,但代价是查找共享对象的开销(通常用 Map);共享对象必须不可变,否则多线程下会相互干扰;不适合"对象数量不多"的场景(管理开销超过节省开销)。
  2. 工程实践:优先复用 JDK 内置享元(Integer/Boolean/String);自己实现享元时配套 FlyweightFactory 管理共享池;避免对可能无界的字符串做 intern();游戏和渲染引擎是享元模式的经典战场。
  3. 常见误区:
按「底层原理 → 设计权衡 → 工程实践」递进排列。

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. Integer a = 128; Integer b = 128; a == b 结果?
  1. 为什么 String 天然是享元?
  1. String.intern() 什么时候会 OOM?
  1. 享元模式什么时候不该用?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,享元模式是 GoF 的创建型设计模式之一,本质是"用共享换内存"。

核心思想是把一个对象拆成两部分——内蕴状态(intrinsic state)和外蕴状态(extrinsic state)。内蕴状态是"多个对象都一样的、不随使用变化的",比如同一个精灵的渲染图;外蕴状态是"每个使用点独有的、可变的",比如这个精灵在屏幕上的位置和旋转角度。把内蕴状态共享,多个对象复用同一份,只让每个使用点持有自己的外蕴状态,就能大幅减少对象数量和内存占用。前提是内蕴状态必须不可变,否则共享对象之间会相互干扰。

Java 中最经典的享元应用有几个。第一是字符串常量池——JVM 把字符串内容作为内蕴状态存到 Heap 的字符串池中,"abc" == "abc" 是同一个引用;String.intern() 可以显式把运行期字符串加入池。要注意 intern() 有个陷阱:如果循环中对大量 unique 字符串(如 UUID、时间戳)调用 intern,会撑爆常量池引发 OOM。

第二是 JDK 的自动装箱缓存。Integer.valueOf() 会缓存 -128 到 127 的整数对象,所以 Integer a = 127; Integer b = 127; a == b 是 true;如果换成 128 就 false 了,因为超出了缓存范围要 new 新对象。同样原理 Boolean.TRUE/FALSE、Byte.valueOf(-128, 127)、Character.valueOf(0, 127) 都是享元。

第三是引擎和游戏场景。文本编辑器里同一个字体的字符渲染可以共享,位置和外蕴信息单独存;游戏里同一精灵的多实例共享渲染图;数据库行对象模板共享。这些场景对象数量大、内蕴状态占比高,是享元模式的经典战场。

常见的误区有两个。第一,Spring 的 singleton scope 不是享元模式——Spring Bean 通常携带业务状态,可变字段多,不是享元需要的"不变量共享"。第二,字符串池和 Metaspace 不是同一个东西——字符串池在 Heap,Metaspace 存类元数据。

享元模式的适用条件是"对象数量大 + 内蕴状态占比高 + 内蕴状态可不可变"。这三个条件不满足时不建议用,管理开销会超过节省开销。