前言
享元模式,将程序中可能反复创建且种类固定的对象缓存起来,以便共享。
通常使用一个享元工厂来创建和缓存享元对象,保证享元类的一个实例只能被创建一次,客户端获取享元对象时,先查看对象是否已经创建,若已经创建,则直接从缓存中获取,否则创建新的对象返回并缓存起来。
实战代码
Integer
JDK Integer 类就使用了享元模式,valueOf 方法将 int 转换为 Integer 对象,从源代码中可以看出来,-128 到 127 这区间内的 int 值是直接从 IntegerCache 中获取的,并不会新建 Integer 对象
IntegerCache 是 Integer 里的静态内部类,可以看到在加载时,便将 -128 到 127 区间创建了对象并缓存起来了。
这么设计的原因是 -128 到 127 这个区间的数值十分常用,就没有必要每次使用时都去新建一个新的 Integer 对象,将该区间的值当作享元对象,即节省了内存空间,也提升了性能。
实战
Integer 类的静态内部类 IntegerCache,实际上就是享元模式中的享元工厂,而区间 [-128, 127] 的整型值就是享元对象。
在实际业务中,只要能抽象出业务的共享对象,再实现与之配套的享元工厂
Flyweight
public interface Flyweight {}
ConcreteFlyweight
public class ConcreteFlyweight implements Flyweight {
private String attr1;
private String attr2;
public ConcreteFlyweight(String attrs) {
String[] as = attrs.split(",");
attr1= as[0];
attr2= as[1];
}
public String getAttr1() {
return this.attr1;
}
public String getAttr2() {
return this.attr2;
}
}
FlyweightFactory
public class FlyweightFactory {
private static FlyweightFactory factory = new FlyweightFactory();
private FlyweightFactory() {}
public static FlyweightFactory getInstance() {
return factory;
}
/**
* 缓存享元对象
* 这里直接使用本地缓存,实际项目中使用 redis 等等
*/
private Map<String, Flyweight> map = new HashMap<>();
/**
* 获取 key 对应的享元对象
* @param key 获取享元对象的key
* @return key对应的享元对象
*/
public synchronized Flyweight getFlyweight(String key) {
// 先从缓存中查找,是否存在 key 对应的 Flyweight 对象
Flyweight obj = map.get(key);
if (null == obj) {
// 不存在,则创建一个新的 Flyweight 对象,并缓存
obj = new ConcreteFlyweight(key);
map.put(key, obj);
}
return obj;
}
}
测试类
public class ClassForTest {
public static void main(String[] args) {
String attrs = "attr1,attr2";
Flyweight obj1 = FlyweightFactory.getInstance().getFlyweight(attrs);
Flyweight obj2 = FlyweightFactory.getInstance().getFlyweight(attrs);
System.out.println(obj1 == obj2);
}
}