享元模式简介

56 阅读4分钟

🎯 享元模式核心要点

关键概念说明示例(DDR4内存条案例)
适用场景系统需要大量创建相似对象,且这些对象存在可共享的稳定状态生产1000条同型号但外观不同的内存条
内部状态对象中不变的、可共享的部分PCB板型号、内存容量、频率参数
外部状态对象中变化的、不可共享的部分(由客户端在使用时传入)散热马甲颜色、RGB灯效模式、贴纸设计
享元工厂管理共享池,确保相同内部状态的对象只创建一次PCBFactory 通过型号+容量+频率生成唯一PCB对象
对象结构最终对象 = 享元对象(内部状态) + 外部状态参数MemoryStick = DDR4PCB + 颜色/灯效参数

class DDR4PCB {
    private final String model;    // 型号(如三星B-Die)
    private final int capacity;    // 容量(如16GB)
    private final int speed;       // 频率(如3200MHz)

    public DDR4PCB(String model, int capacity, int speed) {
        this.model = model;
        this.capacity = capacity;
        this.speed = speed;
    }

    // 核心功能方法(外部状态通过参数传递)
    public void display(String heatSinkColor, String rgbEffect) {
        System.out.printf("【%s】%dGB %dMHz | 马甲色:%s | RGB:%s\n",
                model, capacity, speed, heatSinkColor, rgbEffect);
    }
}

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

    public static DDR4PCB getPCB(String model, int capacity, int speed) {
        String key = model + "_" + capacity + "G_" + speed + "MHz";
        return pool.computeIfAbsent(key, 
            k -> new DDR4PCB(model, capacity, speed));
    }
}

// 完整内存条对象(组合享元+外部状态)
class MemoryStick {
    private DDR4PCB pcb;          // 共享的内部状态
    private String heatSinkColor; // 外部状态
    private String rgbEffect;     // 外部状态

    public MemoryStick(String model, int capacity, int speed, 
                      String color, String rgb) {
        this.pcb = PCBFactory.getPCB(model, capacity, speed);
        this.heatSinkColor = color;
        this.rgbEffect = rgb;
    }

    public void show() {
        pcb.display(heatSinkColor, rgbEffect);
    }
}
public class PCDIY {
    public static void main(String[] args) {
        // 生产1000条不同外观的同规格内存
        List<MemoryStick> memories = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            memories.add(new MemoryStick(
                "三星B-Die", 
                16, 
                3200,
                "渐变" + (i % 10),  // 10种颜色循环
                "彩虹波" + (i % 5)  // 5种灯效模式
            ));
        }

        // 展示第一条内存
        memories.get(0).show();
        // 输出:【三星B-Die】16GB 3200MHz | 马甲色:渐变0 | RGB:彩虹波0
    }
}

📊 内存条案例结构图

                      +-----------------+
                      |   DDR4PCB       |
                      +-----------------+
                      | - model         | ← 内部状态(共享)
                      | - capacity      |
                      | - speed         |
                      +-----------------+
                               ▲
                               |
                      +-----------------+
                      |  PCBFactory     | → 管理PCB对象池
                      +-----------------+
                               │
                               ▼
+------------------+      +-----------------+      +-----------------+
| MemoryStick      |◇---->| DDR4PCB         |      | MemoryStick     |
+------------------+      +-----------------+      +------------------+
| - pcb: DDR4PCB   |      | + display(...) |      | - heatSinkColor | ← 外部状态
| - heatSinkColor  |      +-----------------+      | - rgbEffect     |
| - rgbEffect      |                               +------------------+
+------------------+                               

  1. 正确性

    • ✔️ 将PCB作为内部状态共享 → 避免重复创建相同PCB对象
    • ✔️ 外观特征作为外部状态 → 允许灵活定制不同外观
    • ✔️ 工厂管理确保唯一性 → 相同规格PCB只存在一份
  2. 内存节省效果

    • 传统方式:1000条内存 → 1000个完整对象(每个含PCB参数+外观参数)
    • 享元模式:1个PCB对象 + 1000个外观参数 → 内存占用减少99.9%
  3. 扩展性优势

    • 新增内存外观 → 无需修改PCB相关代码
    • 修改PCB参数 → 只需调整工厂中的共享对象

🚨 注意事项(避免误用)

  1. 不要混淆状态类型

    • 错误做法:将可变属性(如温度传感器读数)作为内部状态 → 导致数据错误
    • 正确做法:内部状态必须是真正不可变的(如硬件型号、数学常量)
  2. 避免过度设计

    • 如果对象数量很少(如只创建10个内存条),直接创建完整对象更简单
    • 享元模式适用于至少数百个对象的场景
  3. 线程安全问题

    // 多线程环境下,工厂需要使用线程安全容器
    public class PCBFactory {
        private static Map<String, DDR4PCB> pool = new ConcurrentHashMap<>();
    }
    

🌰 更多应用场景

行业内部状态(共享)外部状态(动态传入)
游戏开发敌人角色的3D模型/纹理位置、血量、当前动作状态
文档处理字符的字形数据(如字母A的矢量图)字体颜色、在页面中的坐标
交通系统公交车的车型、座位数当前GPS位置、载客量、行驶速度
电商系统商品的基础规格(CPU型号/屏幕参数)用户选择的颜色、定制刻字内容

💡 设计口诀

“不变共享池中存,万变由外灵活传;海量对象不再愁,内存性能双丰收”

下次遇到需要创建大量相似对象时,先问自己:哪些属性是永恒不变的?哪些是千变万化的?