什么是享元模式
“享”的意思是“共享”,“元”的意思是“对象”,所以,“享元”的意思就是“共享对象”。
很简单吧~~
可以认为,单例对象就是享元模式的一种特例,系统中某个特定对象只存在一个,无论外界何时调用,都是这一个对象提供服务。
池化概念也是享元模式的一种体现,比如常量池、线程池、连接池等,都是利用复用对象的途径,达到提高系统整体性能的目的。
“对象共享”是件好事儿,系统资源得到了充分利用,而且修改对象立刻就能全局生效。
但是问题也很明显,那就是多线程环境下的线程安全问题,使用享元模式时,不得不首先考虑对象的安全性,这点必须注意!
设计与实现
理解了享元模式是什么意思,代码的设计就是一件很容易的事情了,只要把握住“共享对象”的原则就好。
总体看来,对象的共享也可以分为很多种情况:
- 对象信息全部共享
- 对象信息部分共享
- 对象共享范围是全局的
- 对象共享范围是局部的
无论上述的哪种细分情况,通常情况下,共享对象都需要有一个可供存储的位置,因为能够找到对象才能谈得上共享对象。
如何存储对象呢?提供四种实现思路,仅供参考。
- 使用单例模式,将对象存储在“类空间”,通过单例类去找共享对象
- 使用
HashMap
的存储结构,使用特定的key
去找共享对象 - 使用数组存储结构,用数组下标去找共享对象
- 在共享范围内,一直持有着共享对象引用
基于上述分析,我个人认为,享元模式的代码设计,灵活度其实非常高,并不存在一个标准的代码设计模版。
Integer应用享元模式
给不出设计模板,就拿JDK
中的Integer
举个例子吧,这里面就包含着享元模式的应用:
public final class Integer extends Number implements Comparable<Integer> {
// 获取一个Integer对象,其中就有部分享元对象
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
// Integer的[-128,127]范围,就是一个缓存池
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
// 省略部分代码
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// 省略部分代码
}
}
}