🎯 享元模式核心要点
| 关键概念 | 说明 | 示例(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 | +------------------+
+------------------+
-
正确性
- ✔️ 将PCB作为内部状态共享 → 避免重复创建相同PCB对象
- ✔️ 外观特征作为外部状态 → 允许灵活定制不同外观
- ✔️ 工厂管理确保唯一性 → 相同规格PCB只存在一份
-
内存节省效果
- 传统方式:1000条内存 → 1000个完整对象(每个含PCB参数+外观参数)
- 享元模式:1个PCB对象 + 1000个外观参数 → 内存占用减少99.9%
-
扩展性优势
- 新增内存外观 → 无需修改PCB相关代码
- 修改PCB参数 → 只需调整工厂中的共享对象
🚨 注意事项(避免误用)
-
不要混淆状态类型
- 错误做法:将可变属性(如温度传感器读数)作为内部状态 → 导致数据错误
- 正确做法:内部状态必须是真正不可变的(如硬件型号、数学常量)
-
避免过度设计
- 如果对象数量很少(如只创建10个内存条),直接创建完整对象更简单
- 享元模式适用于至少数百个对象的场景
-
线程安全问题
// 多线程环境下,工厂需要使用线程安全容器 public class PCBFactory { private static Map<String, DDR4PCB> pool = new ConcurrentHashMap<>(); }
🌰 更多应用场景
| 行业 | 内部状态(共享) | 外部状态(动态传入) |
|---|---|---|
| 游戏开发 | 敌人角色的3D模型/纹理 | 位置、血量、当前动作状态 |
| 文档处理 | 字符的字形数据(如字母A的矢量图) | 字体颜色、在页面中的坐标 |
| 交通系统 | 公交车的车型、座位数 | 当前GPS位置、载客量、行驶速度 |
| 电商系统 | 商品的基础规格(CPU型号/屏幕参数) | 用户选择的颜色、定制刻字内容 |
💡 设计口诀
“不变共享池中存,万变由外灵活传;海量对象不再愁,内存性能双丰收”
下次遇到需要创建大量相似对象时,先问自己:哪些属性是永恒不变的?哪些是千变万化的?