结构型-享元模式
# 什么是享元模式?
- Flyweight Design Pattern
- 享元模式的意图是复用对象,节省内存,前提是享元对象是不可变的。
- 当一个系统中存在大量重复对象的时候,如果这些重复对象是不可变对象,我们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。
- 定义中的“不可变对象”,一旦通过构造函数初始化完成之后,它的状态就不会再被修改了。
- 享元模式的代码实现,主要通过工厂模式,在工厂类中,通过一个 Map 来缓存已经创建过的享元对象,来达到复用的目的。
# 享元模式 VS 单例
- 创建个数
- 单例模式:一个类只能创建一个对象。
- 享元模式:一个类可以创建多个对象,每个对象被多处代码引用。
- 复用层面
- 单例模式:使用单例模式,为了限制同一个对象的个数。
- 享元模式:为了对象复用,节省内存。
# 享元模式 vs 缓存
- 缓存:一般指数据库缓存,为了提高访问效率,而非复用。
- 享元模式:事先缓存,主要为了复用。
# 在 Java Integer 中的应用
Integer i = 56; //自动装箱
// Integer i = 56;底层执行了:Integer i = Integer.valueOf(56);
int j = i; //自动拆箱
// 底层执行了:int j = i.intValue();
1
2
3
4
5
6
2
3
4
5
6
# 原理
因为 Integer 用到了享元模式来复用对象,才导致了这样的运行结果。当我们通过自动装箱,也就是调用 valueOf() 来创建 Integer 对象的时候,如果要创建的 Integer 对象的值在 -128 到 127 之间,会从 IntegerCache 类中直接返回,否则才调用 new 方法创建。
# 设置
//方法一:
-Djava.lang.Integer.IntegerCache.high=255
//方法二:
-XX:AutoBoxCacheMax=255
1
2
3
4
5
2
3
4
5
# 在 String 类中应用
- String 类的享元模式的设计,跟 Integer 类稍微有些不同。Integer 类中要共享的对象,是在类加载的时候,就集中一次性创建好的。
- 对于字符串来说,我们没法事先知道要共享哪些字符串常量,所以没办法事先创建好,只能在某个字符串常量第一次被用到的时候,存储到常量池中,当之后再用到的时候,直接引用常量池中已经存在的即可,就不需要再重新创建了。
# 享元模式缺点
- 对于 JVM 的垃圾回收并不友好,享元工厂类一直保存了对象的引用,导致享元对象在没有任何代码使用的情况下,也不会被垃圾回收掉。
上次更新: 2020/10/18, 14:10:00