《享元模式》|设计模式系列第12篇
系列:结构型模式 · 享元模式(Flyweight Pattern)
关键词:对象池、复用实例、内部状态、外部状态、减少内存占用
一、什么是享元模式
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象。

属于结构型设计模式。
简单理解:
当系统需要创建大量相似小对象时,把对象拆分为内部状态和外部状态。内部状态不变,可以全局共享复用;外部状态由客户端传入,不存储在享元对象内部。通过对象池复用已有实例,避免重复创建大量对象,节约内存。
例子:五子棋棋子,棋子颜色是内部状态可共享;棋子坐标是外部状态,每次下棋动态传入。
核心意图
共享细粒度对象,降低内存开销;区分内部状态与外部状态。
适用场景
- 系统存在大量重复细粒度对象,内存占用高
- 对象大部分属性可以抽离为不变的内部状态
- 对象创建成本较高,适合缓存复用
- 可以将对象可变部分提取为外部状态,由客户端传入
⚠️ 缺点预警:需要拆分内部/外部状态,增加代码复杂度;为了节省内存,带来额外的查询逻辑开销。
二、UML结构图
角色划分:
- Flyweight(抽象享元):声明接口,接收外部状态
- ConcreteFlyweight(具体享元):实现抽象享元,存储内部状态,可共享
- UnsharedConcreteFlyweight(非共享享元):不需要共享的享元(可选)
- FlyweightFactory(享元工厂):维护享元池,负责创建、复用享元实例
- Client(客户端):计算/维护外部状态,调用享元对象

三、Java 完整示例
场景:ChessPiece 棋子,color 为内部状态(共享);x,y 坐标为外部状态(客户端传入)。
代码全部使用英文。
1. Flyweight 抽象享元
public abstract class ChessPiece {
protected String color;
public abstract void display(int x, int y);
}
2. ConcreteFlyweight 具体享元
public class ConcreteChessPiece extends ChessPiece {
public ConcreteChessPiece(String color) {
this.color = color;
}
@Override
public void display(int x, int y) {
System.out.println("Piece color:" + color + ", position:(" + x + "," + y + ")");
}
}
3. FlyweightFactory 享元工厂
import java.util.HashMap;
import java.util.Map;
public class ChessPieceFactory {
private Map<String, ChessPiece> pool = new HashMap<>();
public ChessPiece getChessPiece(String color) {
if (!pool.containsKey(color)) {
pool.put(color, new ConcreteChessPiece(color));
}
return pool.get(color);
}
public int getPoolSize() {
return pool.size();
}
}
4. Client 客户端
public class Client {
public static void main(String[] args) {
ChessPieceFactory factory = new ChessPieceFactory();
ChessPiece black1 = factory.getChessPiece("black");
black1.display(1, 2);
ChessPiece black2 = factory.getChessPiece("black");
black2.display(3, 4);
ChessPiece white1 = factory.getChessPiece("white");
white1.display(5, 6);
System.out.println("Total shared objects in pool: " + factory.getPoolSize());
System.out.println("black1 == black2 ? " + (black1 == black2));
}
}
运行输出:
Piece color:black, position:(1,2)
Piece color:black, position:(3,4)
Piece color:white, position:(5,6)
Total shared objects in pool: 2
black1 == black2 ? true
无论创建多少个黑色棋子,内存中只有一份 black 享元对象;坐标 x,y 每次调用由客户端传入,不存放在享元对象。
四、内部状态 vs 外部状态
- Internal State:不变、不随场景变化,可以共享,保存在享元对象内部。如棋子颜色。
- External State:可变,由客户端维护,调用时传入,不保存在享元对象。如棋子坐标。
五、优缺点总结
✅ 优点
- 大量细粒度对象场景下,显著节约内存
- 对象复用,减少对象创建销毁开销
❌ 缺点
- 需要分离内外状态,增加系统复杂度
- 运行时需要传递外部状态,增加调用开销
六、框架源码应用
- JDK
String常量池,典型享元思想 - Integer.valueOf() 缓存池(-128 ~ 127)
- Spring 线程池、连接池都属于享元思想延伸
七、小结
享元模式核心:拆分内外状态,通过工厂池复用不变对象,可变参数外部传入。
适用判断:大量相似对象,并且可以拆分出不变内部状态。如果对象状态全部是可变的,不适合享元。
0 条笔记