什么是享元模式?
享元模式(Flyweight Pattern)是一种结构型设计模式 ,其核心思想是通过共享技术有效地支持大量细粒度对象的复用,从而减少内存中对象的数量,降低系统资源消耗。
享元模式适用于以下场景:
- 系统中存在大量相似或重复的对象;
- 这些对象的大部分状态可以外部化(即可以抽离为外部参数);
- 对象的内部状态(享元对象共享的部分)一旦创建就不改变(通常是不可变的);
- 应用需要在性能和内存之间取得平衡。
享元模式通常包含以下几个角色:
- Flyweight(抽象享元类):定义对象的接口,通过参数接受外部状态;
- ConcreteFlyweight(具体享元类):实现抽象享元接口,内部状态存储在对象内部;
- UnsharedConcreteFlyweight(非共享享元类):不共享的对象,通常作为组合结构的一部分;
- FlyweightFactory(享元工厂):创建并管理享元对象,确保共享对象不被重复创建;
- Client(客户端):维持对享元对象的引用,并计算/传递外部状态。
享元模式的关键在于区分内部状态 (共享、不变)和外部状态(由客户端维护、随环境变化)。
Java中Integer是如何应用享元模式的?
Java 中的 Integer
类通过 IntegerCache
实现了享元模式。在 Integer.valueOf(int i)
方法中,对 -128 到 127 范围内的整数进行了缓存:
java
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这意味着:
✅ 在 -128 到 127 范围内,使用 Integer.valueOf()
或自动装箱时,会返回缓存池中的同一个对象实例:
java
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true ------ 同一个对象引用
❌ 超出该范围时,每次都会创建新对象:
java
Integer x = 200;
Integer y = 200;
System.out.println(x == y); // false ------ 不同对象引用
⚠️ 注意:应使用 .equals()
方法比较值是否相等,而不是 ==
(后者比较的是引用)。
该缓存范围可通过 JVM 参数
-XX:AutoBoxCacheMax=N
调整上限(下限固定为 -128)。
这种设计减少了小整数频繁创建对象的开销,是享元模式的经典应用。
享元模式的其他应用?
-
String 常量池
Java 中的字符串字面量会被缓存在字符串常量池中,相同的字符串字面量共享同一对象:
javaString s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2); // true
-
数据库连接池 / 线程池
虽然不完全符合传统享元定义,但思想类似 ------ 复用昂贵资源,避免重复创建和销毁。
-
GUI 系统中的字体、颜色对象
在图形界面中,相同字体或颜色对象可被多个控件共享,避免重复实例化。
-
游戏开发中的粒子系统
大量相似粒子(如爆炸火花、雨滴)共享纹理、行为等内部状态,位置、速度等作为外部状态传入。
-
文本编辑器中的字符对象
每个字符(如 'a')在文档中可能重复出现成千上万次,享元模式可让所有 'a' 共享同一个字符对象,仅位置、样式等作为外部状态。
-
Java 中的
Boolean
、Byte
、Short
、Long
、Character
缓存类似
Integer
,这些包装类也对部分值范围做了缓存(如Boolean
缓存TRUE
和FALSE
,Character
缓存 0~127)。
✅ 总结:享元模式在需要"大量重复对象 + 内存敏感"的场景中非常有用,是空间换时间的经典优化手段。
❤️这里是 软件柠檬, 让我们一起学习进步~❤️