享元模式
享元模式用于共享大量细粒度对象,减少内存占用。
一句话理解:相同的部分复用,不同的部分外部传入。
解决什么问题
如果系统中有大量相似对象,每个对象都保存一份重复数据,会浪费内存。
例如:
- 文本编辑器中大量字符对象。
- 地图中大量图标对象。
- 游戏中大量子弹、树木、粒子。
- 权限系统中大量重复权限项。
享元模式把对象状态分成两类:
| 状态 | 含义 | 存放位置 |
|---|---|---|
| 内部状态 | 可共享、不随场景变化 | 享元对象内部 |
| 外部状态 | 不可共享、随场景变化 | 调用时传入 |
基本结构
text
FlyweightFactory -> 缓存享元对象
Flyweight -> 共享内部状态
Client -> 传入外部状态Java 示例
地图图标类型是内部状态,可以共享:
java
class MapIcon {
private final String type;
private final String imagePath;
MapIcon(String type, String imagePath) {
this.type = type;
this.imagePath = imagePath;
}
public void draw(int x, int y) {
System.out.println("draw " + type + " at " + x + "," + y + " with " + imagePath);
}
}享元工厂:
java
import java.util.HashMap;
import java.util.Map;
class MapIconFactory {
private final Map<String, MapIcon> cache = new HashMap<>();
public MapIcon getIcon(String type) {
return cache.computeIfAbsent(type, key -> {
if ("shop".equals(key)) {
return new MapIcon("shop", "/icons/shop.png");
}
if ("hospital".equals(key)) {
return new MapIcon("hospital", "/icons/hospital.png");
}
return new MapIcon("default", "/icons/default.png");
});
}
}使用:
java
MapIconFactory factory = new MapIconFactory();
factory.getIcon("shop").draw(10, 20);
factory.getIcon("shop").draw(30, 40);
factory.getIcon("hospital").draw(50, 60);shop 图标对象只创建一次,坐标作为外部状态传入。
JDK 中的例子
字符串常量池、包装类型缓存都体现了共享思想。
java
Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // true小整数范围内复用缓存对象,避免重复创建。
使用场景
- 大量相似对象。
- 对象内部有可共享状态。
- 外部状态可以从对象中剥离出来。
- 内存占用是实际问题。
优点
- 减少对象数量。
- 降低内存占用。
- 可以集中管理共享对象。
缺点
- 需要区分内部状态和外部状态。
- 代码复杂度会增加。
- 外部状态传递不当会导致错误。
- 并发场景要注意缓存线程安全。
实战注意
享元模式不是缓存所有对象。只有当大量对象真的共享相同内部状态,并且对象数量造成资源压力时,才值得引入。