1. 享元模式定义:
享元模式是池技术的重要实现原理,定义如下:使用共享对象可以有效的支持大量的细粒度对象
内部状态:存储在享元对象内部不随外部环境改变可以共享出来的信息
外部状态:外部状态是对象得以依赖的一个标记,是随外部环境改变而变化、不可以共享的状态
2. 享元模式的角色名称:
a. 抽象享元角色
简单地说,就是一个产品的抽象类,它同时定义了对象的内部状态和外部状态,以及接口和实现
b. 具体的享元对象
具体的产品类,实现了抽象产品类定义的业务
c. 享元工厂
提供一个池容器,同时提供从池中获取对象的方法
3. 享元模式通用示例代码:
抽象享元角色类:
public abstract class FlyWeight { //内部状态 private String intrinsic; private String name; //外部状态 protected final String extrinsic; //要求享元角色必须接受外部状态 public FlyWeight(String extrinsic) { this.extrinsic=extrinsic; } //定义业务操作 public abstract void operator(); //内部状态的getter/setter public String getIntrinsic() { return intrinsic; } public void setIntrinsic(String intrinsic) { this.intrinsic = intrinsic; } public String getName() { return name; } public void setName(String name) { this.name = name; } }抽象享元角色类一般是一个抽象类,一般要把外部状态和内部状态定义出来,避免子类随意的扩展。
具体的享元角色类:
public class FlyWeight1 extends FlyWeight{ public FlyWeight1(String extrinsic) { super(extrinsic); } @Override public void operator() { System.out.println("业务操作方法...内部状态是:"+super.getIntrinsic()); } }享元工厂类:
public class FlyWeightFactory { private static HashMap<String,FlyWeight> pool=new HashMap<String,FlyWeight>(); public static FlyWeight getInstance(String key){ //需要返回的对象 FlyWeight flyWeight=null; //如果池中存在该对象,直接获取返回 if(pool.containsKey(key)){ System.out.println(key+"-----池中存在,直接从对象池中取得"); flyWeight=pool.get(key); }else{ //池中不存在此对象,根据外部状态新建一个对象返回 System.out.println(key+"-----池中不存在,建立对象并放到对象池中"); flyWeight=new FlyWeight1(key); //放置到池中 pool.put(key, flyWeight); } return flyWeight; } /** * 初始化对象池 * @param size */ public static void initObjectPool(int size){ for (int i = 0; i <= size; i++) { FlyWeightFactory.getInstance("对象"+i); } } }测试类:
public class Test { public static void main(String[] args) { //初始化对象池 FlyWeightFactory.initObjectPool(4); FlyWeight flyWeight=FlyWeightFactory.getInstance("对象1"); flyWeight.setIntrinsic("这是单独设置的内部状态!"); flyWeight.operator(); } }结果:
对象0-----池中不存在,建立对象并放到对象池中 对象1-----池中不存在,建立对象并放到对象池中 对象2-----池中不存在,建立对象并放到对象池中 对象3-----池中不存在,建立对象并放到对象池中 对象4-----池中不存在,建立对象并放到对象池中 对象1-----池中存在,直接从对象池中取得 业务操作方法...内部状态是:这是单独设置的内部状态!4. 享元模式的优点和缺点
享元模式是可以大大减少应用程序创建对象的时间,降低程序内存的占用,增强程序的性能,同时它也大大加大了程序的复杂度,因为需要分离外部状态和内部状态。
5. 享元模式的使用场景
在如下场景中则可以选择使用享元模式。
● 系统中存在大量的相似对象。
● 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份。
● 需要缓冲池的场景。
6. 享元模式的线程安全问题:
由于使用的是共享对象,所以很可能会出现2个线程共用一个对象并且同时修改的问题,这样就会出现线程安全问题。为了尽可能避免这个问题,要尽量的加大对象池中对象的数量,并且对于外部状态,最好可以使用多个字符串的组合来确定key值(即对象池中,一个对象对应一个key值)