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值)