享元模式


享元模式

享元模式:是一种重要的池技术的实现方式,使用共享对象可有效地支持大量的细粒度的对象。
享元模式的定义提出了两个要求:细粒度的对象和共享对象,分配太多的对象到应用程序当中去将有损程序的性能,而且还容易造成内存溢出,通过享元模式的共享对象的技术来解决这些问题。首先我们先了解一下对象的内部状态(intrinsic)和外部状态(extrinsic)。

内部状态:对象可共享出来的信息,存储在享元对象的内部并且不会随环境改变而改变,作为一个对象的动态附加信息,不必直接存储在具体某个对象中。
外部状态:对象得以依赖的一个标记,随环境的改变而改变、不可共享的状态,是一批对象的统一标识,是唯一的一个索引值。

有了对象的两种状态,我们来看一下享元模式的通用类图:

public abstract class Flyweight {

//内部状态
private String intrinsic;
//外部状态
protected final String extrinsic;
public Flyweight(String extrinsic){
    this.extrinsic = extrinsic;
}
public abstract void operate();
public String getIntrinsic(){
    return this.intrinsic;
}
public void setIntrinsic(String intrinsic){
    this.intrinsic = intrinsic;
}

}

public class ConcreteFlyweight1 extends Flyweight{

public ConcreteFlyweight1(String extrinsic) {
    super(extrinsic);
    // TODO Auto-generated constructor stub
}

@Override
public void operate() {
    // TODO Auto-generated method stub
    
}

}

public class FlyweightFactory {

private static HashMap<String, Flyweight> flyWeights = new HashMap<String, Flyweight>();
public static Flyweight getFlyweight(String key){
    Flyweight flyweight = null;
    if(flyWeights.containsKey(key)){
        flyweight = flyWeights.get(key);
    }else{
        //根据外部状态创建享元对象
        flyweight = new ConcreteFlyweight1(key);
        //将享元对象放到池中
        flyWeights.put(key, flyweight);
    }
    return flyweight;
}

}

View Code

享元模式的优缺点

    享元模式是一个非常简单的模式,它可以大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能,但同时也提高了系统的复杂性,需要分离出外部状态和内部状态,而外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统逻辑混乱。

享元模式的使用场景

系统中存在大量的相似对象;
细粒度的对象具备较近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;
需要缓冲池的场景。

享元模式的扩展

线程安全问题,当多个线程同时从对象缓冲池中取对象,并对对象的内部状态进行修改时,可能会造成线程的不安全。

public class MultiThread extends Thread{

private Flyweight flyweight;
private String intrinsic;
public MultiThread(Flyweight flyweight){
    this.flyweight = flyweight;
    this.intrinsic = flyweight.getIntrinsic();
}
public void run(){
    String intrinsic = flyweight.getIntrinsic();
    if(!intrinsic.equalsIgnoreCase(this.intrinsic)){
        System.out.print("线程不安全......");
        System.out.println(this.intrinsic + "     " + intrinsic);
    }
}

}

public class Client {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Flyweight flyweight = FlyweightFactory.getFlyweight("123");
    while(true){
        flyweight.setIntrinsic("intrinsic1");
        new MultiThread(flyweight).start();
        flyweight.setIntrinsic("intrinsic2");
        new MultiThread(flyweight).start();
    }
}

}

View Code

性能问题,尽量使用Java基本类型作为外部状态(即为key),如果自定义对象作为外部状态会降低系统执行的效率。

声明:DungCry.|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 享元模式


以此热爱,以此谋生。
Le vent se lève, il faut tenter de vivre