Skip to content
Method约 1 分钟0 个小节更新于 2026/06/19在线编辑

享元模式

享元模式用于共享大量细粒度对象,减少内存占用。

一句话理解:相同的部分复用,不同的部分外部传入。

解决什么问题

如果系统中有大量相似对象,每个对象都保存一份重复数据,会浪费内存。

例如:

  • 文本编辑器中大量字符对象。
  • 地图中大量图标对象。
  • 游戏中大量子弹、树木、粒子。
  • 权限系统中大量重复权限项。

享元模式把对象状态分成两类:

状态含义存放位置
内部状态可共享、不随场景变化享元对象内部
外部状态不可共享、随场景变化调用时传入

基本结构

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

小整数范围内复用缓存对象,避免重复创建。

使用场景

  • 大量相似对象。
  • 对象内部有可共享状态。
  • 外部状态可以从对象中剥离出来。
  • 内存占用是实际问题。

优点

  • 减少对象数量。
  • 降低内存占用。
  • 可以集中管理共享对象。

缺点

  • 需要区分内部状态和外部状态。
  • 代码复杂度会增加。
  • 外部状态传递不当会导致错误。
  • 并发场景要注意缓存线程安全。

实战注意

享元模式不是缓存所有对象。只有当大量对象真的共享相同内部状态,并且对象数量造成资源压力时,才值得引入。

以工程实践沉淀知识,以文档复盘成长。