设计模式-享元模式

192 阅读3分钟

享元模式的定义

享元模式是池技术的重要实现方式,其定义如下:使用共享对象可以有效地支持大量细粒度的对象

享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象,不可变对象是指:一旦通过构造函数初始化完成之后,它的状态(对象的成员变量或者属性)就不会发生修改了,所以不可变对象不可以暴露任何set()等修改内部状态的方法

享元模式的实现其实很简单,主要是通过工厂模式,在工厂类中,通过一个Map来缓存已经创建过的享元对象

享元模式通用类图

image-20200806154108137

  • Flyweight(抽象享元角色)

    它简单的说就是一个产品的抽象类,同时定义出对象的外部状态和内部状态的接口或实现

  • ConcreateFlyweight(具体享元对象)

    具体的一个产品类,实现抽象角色定义的业务,该角色中需要注意的是内部状态处理应该与环境无关,不应该出现一个操作修改了内部状态,同时修改了外部状态,这是绝对不允许的

  • unsharedConcreteFlyweight(不可共享的享元对象)

    不存在外部状态或者安全要求(如线程安全)不能够使用共享技术的对象,该对象一般不出现在享元工厂中

  • FlyweightFactory(享元工厂)

    职责非常简单,就是构造一个池容器,同时提供从池中获得对象的方法

/**
 * @author cuckooYang
 * @create 2020-08-06 15:55
 * @description 抽象享元对象
 **/

public abstract class Flyweight {

    //内部状态
    private String intrinsic;
    //外部状态
    protected final String Extrinsic;
    //要求享元对象必须接受外部状态
    public Flyweight(String _Extrinsic){
        this.Extrinsic = _Extrinsic;
    }
    //定义业务操作
    public abstract void operator();

    //内部状态的set,get
    public String getIntrinsic() {
        return intrinsic;
    }

    public void setIntrinsic(String intrinsic) {
        this.intrinsic = intrinsic;
    }

抽象享元角色一般为抽象类,在实际项目中,一般是一个实现类,它是描述一类事物的方法。在抽象角色中,一般需要把外部状态和内部状态(当然了,可以没有内部状态,只有行为也是可以的)定义出来,避免子类的随意扩展。

/**
 * @author cuckooYang
 * @create 2020-08-06 16:17
 * @description 具体享元对象
 **/

public class ConcreateFlyweight1 extends Flyweight {

    //接受外部状态
    public ConcreateFlyweight1(String _Extrinsic) {
        super(_Extrinsic);
    }
    //根据外部状态进行逻辑处理
    @Override
    public void operator() {
        //业务逻辑
    }

}
class ConcreateFlyweight2 extends Flyweight {

    //接受外部状态
    public ConcreateFlyweight2(String _Extrinsic) {
        super(_Extrinsic);
    }
    //根据外部状态进行逻辑处理
    @Override
    public void operator() {
        //业务逻辑
    }

}

这很简单,实现自己的业务逻辑,然后接收外部状态,以便内部业务逻辑对外部状态的依赖。注意,我们在抽象享元中对外部状态加上了final关键字,防止意外产生,什么意外?获得了一个外部状态,然后无意修改了一下,池就混乱了!

/**
 * @author cuckooYang
 * @create 2020-08-06 16:21
 * @description 享元工厂
 **/

public class FlyweightFactory {

    //定义一个池容器
    private static HashMap<String,Flyweight> pool = new HashMap<>();

    //享元工厂
    public static Flyweight getFlyweight(String Extrinsic){
        //需要返回的对象
        Flyweight flyweight = null;
        //在池中没有对象
        if(pool.containsKey(Extrinsic)){
            flyweight = pool.get(Extrinsic);
        }else{
            //根据外部状态创建享元对象
            flyweight = new ConcreateFlyweight1(Extrinsic);
            //放置到池中
            pool.put(Extrinsic,flyweight);
        }
        return flyweight;
    }
}

享元模式优缺点

享元模式减少了应用程序创建的对象,降低了程序内存的占用,增强了程序的性能,但是它也提高了程序的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随着内部状态的变化而变化,否则会导致系统的逻辑混乱

享元模式的使用场景

  • 系统中存在大量相似的对象
  • 细粒度对象都具备较为接近的外部状态,而且内部状态与环境无关
  • 需要缓冲池的场景