1. 定义
享元模式(Flyweight Pattern)是一种结构型设计模式,其核心思想是通过共享对象来减少内存的使用和提高系统性能。享元模式通过将内部可共享的状态和外部独立的状态分离,从而减少对象的重复创建。
2. 适用场景
享元模式适用于以下情况:
- 对象数量庞大,且大多数对象可以共享部分状态。
- 内存消耗高,有必要通过对象复用来优化性能。
- 外部状态可独立存储,共享的对象可以被多个外部对象同时使用。
3. 模式结构
享元模式主要由以下几个部分构成:
- Flyweight接口:定义享元对象的接口,包含需要实现的业务方法。
- ConcreteFlyweight(具体享元类):实现 Flyweight 接口,提供共享的内部状态。
- UnsharedConcreteFlyweight(非共享享元类):定义那些不被共享的对象。
- FlyweightFactory(享元工厂类):用于管理享元对象,提供共享对象的缓存机制。
- Client(客户端):负责存储和操作外部状态,并使用享元对象完成具体任务。
4. 享元模式的核心:内部状态与外部状态
- 内部状态:可以共享的部分,不会随外部变化。由享元对象内部维护。
- 外部状态:不可共享的部分,会随环境改变。由客户端维护或传递给享元对象。
5. 实例:JDK 中 Integer 的缓存机制
在 Java 中,Integer
类为了提高性能和减少内存消耗,对 -128
到 127
之间的整数进行了缓存,这是享元模式的一个典型应用。
5.1 Integer 缓存的工作原理
当你对一个 Integer
对象进行自动装箱或通过 Integer.valueOf()
创建时,JVM 会检查数字是否在缓存范围(-128
到 127
)内:
- 如果在此范围内,返回缓存中的对象。
- 如果超出该范围,创建新的
Integer
对象。
Integer i1 = 127; // 自动装箱,相当于 Integer.valueOf(127)
Integer i2 = 127; // 直接从缓存中获取
Integer i3 = 128; // 创建新的对象,因为超出缓存范围
Integer i4 = 128; // 再次创建新的对象
5.2 Integer 缓存的源码
Integer.valueOf()
方法通过内部的 IntegerCache
类来实现缓存机制:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) {
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high = 127;
static final Integer cache[];
static {
cache = new Integer[(high - low) + 1];
for (int i = 0, j = low; j <= high; i++, j++) {
cache[i] = new Integer(j);
}
}
}
在此代码中,IntegerCache
类缓存了 -128
到 127
之间的 Integer
对象。调用 Integer.valueOf()
时,如果数字在缓存范围内,则返回缓存对象,避免创建新的对象。
5.3 实例演示
public class FlyweightExample {
public static void main(String[] args) {
Integer i1 = Integer.valueOf(127);
Integer i2 = Integer.valueOf(127);
Integer i3 = Integer.valueOf(128);
Integer i4 = Integer.valueOf(128);
System.out.println(i1 == i2); // true, 127在缓存范围内,共享对象
System.out.println(i3 == i4); // false, 128不在缓存范围内,不同对象
}
}
输出结果:
true
false
5.4 内部状态与外部状态的应用
- 内部状态:在
-128
到127
之间的整数是共享的,表示可重复使用的部分(享元模式中的共享对象)。 - 外部状态:超出此范围的整数需要每次新建,是不可共享的部分。
6. 享元模式总结
优点:
- 减少内存开销:通过共享相同的对象,减少了重复对象的创建,尤其在大量小对象场景中非常有效。
- 提高性能:减少了对象的创建和销毁过程,尤其在大量使用相似对象时性能提升显著。
缺点:
- 增加代码复杂度:需要区分内部状态和外部状态,额外的状态管理会增加代码复杂度。
- 适用场景有限:仅在对象可共享且变化不大时效果显著,不适用于复杂对象或场景。
7. 适用案例
- JDK 中 Integer 的缓存机制:
Integer
类缓存了-128
到127
之间的整数,避免重复创建相同数值的对象,节省内存。 - 文本编辑器中的字符对象:同样字符的对象可以共享字体、大小等属性,只需根据不同位置设定外部状态(坐标)。
- 游戏中的精灵对象:相同的精灵图片资源可以共享,不同精灵的位置和行为通过外部状态来控制。
8. 模式应用要点
享元模式的核心是通过分离共享的内部状态和不可共享的外部状态来实现对象的重用。在实际开发中,常见的场景如缓存、池化资源管理等,都可以通过享元模式来实现内存优化。
评论 (0)