定义
享元模式以共享的方式高效地支持大量的细粒度对象。是结构型创建模式。
UML
角色
- FlyWeight: 抽象享元接口
- ConcreteFlyWeight: 具体享元类,实现了享元类。该类对象在创建时便初始化内蕴状态。
- FlyWeightFactory: 享元对象创建与管理工厂类。当创建一个享元对象时,先在工厂所维护的集合中查找是否存在可以共享的对象,存在则直接返回,不存在则创建并加入集合中。
内蕴状态:是存储在享元对象内部并且不会随环境的改变而改变。
示例
/**
* desc : 享元接口
* Created by tiantian on 2018/10/16
*/
public interface FlyWeight {
void option();
String getIntrinsicState();
}
具体享元类A具有不可变的内蕴状态intrinsicState,创建对象时指定。
/**
* desc : 具体享元类A
* Created by tiantian on 2018/10/16
*/
public class ConcreteFlyWeightA implements FlyWeight{
private String intrinsicState;
public ConcreteFlyWeightA(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void option() {
System.out.println("ConcreteFlyWeightA option()");
}
@Override
public String getIntrinsicState() {
return intrinsicState;
}
}
具体享元类B与具体享元类A相似
/**
* desc : 具体享元类B
* Created by tiantian on 2018/10/16
*/
public class ConcreteFlyWeightB implements FlyWeight{
private String intrinsicState;
public ConcreteFlyWeightB(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void option() {
System.out.println("ConcreteFlyWeightB option()");
}
@Override
public String getIntrinsicState() {
return intrinsicState;
}
}
FlyWeightFactory负责创建享元对象并维护享元对象构成的集合,这里使用单例模式实现。此单例模式的实现是静态内部类的方式,这样的好处是:不使用该享元工厂时不必创建工厂对象,只有当初次调用getInstance()方法时才会出发JVM加载此内部类完成对象创建工作。同时JVM只加载一次该静态内部类,故不必使用任何同步手段即可实现单例对象的创建。addFlyWeight方法向享元对象集合中新增享元对象,使用synchronized修饰避免线程不安全隐患。
/**
* desc : 享元对象工厂(使用单例)
* Created by tiantian on 2018/10/16
*/
public class FlyWeightFactory {
private static Map<String,FlyWeight> flyWeightMap = new HashMap();
final static class FactoryHolder {
private static FlyWeightFactory flyWeightFactory = new FlyWeightFactory();
}
public FlyWeight creatFlyWeight(String intrinsicState) {
if (flyWeightMap.get(intrinsicState) != null) {
return flyWeightMap.get(intrinsicState);
}
ConcreteFlyWeightA cfwA = new ConcreteFlyWeightA(intrinsicState);
addFlyWeigth(cfwA);
return cfwA;
}
public static FlyWeightFactory getInstance() {
return FactoryHolder.flyWeightFactory;
}
private synchronized static void addFlyWeigth(FlyWeight flyWeight) {
flyWeightMap.put(flyWeight.getIntrinsicState(), flyWeight);
}
}
public class Test {
public static void main(String[] args) {
FlyWeightFactory factory = FlyWeightFactory.getInstance();
FlyWeight firstFlyWeightA = factory.creatFlyWeight("firstFlyWeightA");
firstFlyWeightA.option();
// 再次创建firstFlyWeightA的FlyWeight对象
// 打印:ConcreteFlyWeightA option()
FlyWeight firstFlyWeightA1 = factory.creatFlyWeight("firstFlyWeightA");
// 打印:true,
// 说明返回的是之前创建的对象
System.out.println(firstFlyWeightA == firstFlyWeightA1);
}
}
测试显示结果表明当创建相同内蕴状态名称的享元对象时不会新增对象,正好符合我们的预期。
总结
享元模式的使用还算较多。比如java中String对象的创建,如果存在相同字符串的String对象则返回,没有则在字符串常量池中创建。再比如说数据库连接池也是一种高效对象复用方式,当需要连接数据库时先从连接池中获取连接,用完之后数据库连接池再回收此连接对象以复用。