Skip to content

享元模式 低频

享元模式(Flyweight Pattern)通过共享尽可能多的细粒度对象来有效支持大量细粒度对象的重用,减少内存占用。它将对象的状态分为内部状态(可共享,不变)和外部状态(不可共享,随上下文变化)。

优缺点

优点缺点
大幅减少内存中相似对象的数量需要分离内/外部状态,增加逻辑复杂度
缓存共享对象,提升系统性能以时间换空间,享元工厂查找可能增加耗时
外部状态独立存储,不影响共享如果内部状态设计不合理,可能导致线程安全问题

适用场景

  • 系统有大量相似对象,造成内存开销过高
  • 对象的大部分状态可以外部化,剥离后对象可共享
  • 需要缓存池来管理对象的场景

享元模式

java
import java.util.HashMap;
import java.util.Map;

// 享元接口
interface Tree {
    void display(int x, int y);  // x, y 是外部状态(位置)
}

// 具体享元:树木类型(内部状态:名称、颜色、纹理)
class TreeType implements Tree {
    private final String name;   // 内部状态 —— 不变,可共享
    private final String color;
    private final String texture;

    public TreeType(String name, String color, String texture) {
        this.name = name;
        this.color = color;
        this.texture = texture;
    }

    @Override
    public void display(int x, int y) {
        System.out.printf("%s(%s,%s)位于 (%d, %d)%n", name, color, texture, x, y);
    }
}

// 享元工厂
class TreeFactory {
    private static final Map<String, TreeType> pool = new HashMap<>();

    public static TreeType getTreeType(String name, String color, String texture) {
        String key = name + "|" + color + "|" + texture;
        // 存在则返回共享对象,不存在则创建
        return pool.computeIfAbsent(key, k -> {
            System.out.println("→ 创建新树类型: " + name);
            return new TreeType(name, color, texture);
        });
    }

    public static int poolSize() {
        return pool.size();
    }
}

// 客户端:每棵树有独立位置
class Forest {
    public static void main(String[] args) {
        // 种植 10000 棵树,但只有 2 种树类型
        for (int i = 0; i < 5000; i++) {
            TreeType oak = TreeFactory.getTreeType("橡树", "绿", "粗糙");
            oak.display(i, i % 100);
        }
        for (int i = 0; i < 5000; i++) {
            TreeType pine = TreeFactory.getTreeType("松树", "深绿", "鳞片");
            pine.display(i, i % 100);
        }
        System.out.println("池中享元对象数: " + TreeFactory.poolSize()); // 2
    }
}

状态区分

状态类型特征示例
内部状态不变、可共享、存储在享元对象内部树的类型、颜色、纹理
外部状态随上下文变化、由客户端维护树的位置坐标

经典应用

  • String 常量池:JVM 复用字符串字面量
  • Integer 缓存Integer.valueOf(-128 ~ 127) 返回缓存对象
  • 线程池:复用线程对象
  • Java 中的 String#intern()

如有转载或 CV 请标注本站原文地址