介绍
享元模式的目的是在大量细密度的情况下减少创建对象的数量,从而减少程序对系统性能内存的占用。
核心思路是将大量对象的共同部分抽象出来,系统存储内存中的对象实例,如果需要创建新的对象,通过查询共同部分查询系统中是否存在已有对象实例,如果有的话直接从内存中返回已有对象,避免重复创建。
该模式并不是所有情况下都合适,使用时需要注意。
享元模式结构
内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。
享元模式的一个核心特点就是需要给对象划分出内部状态与外部状态,其中外部状态最好是不应随着内部状态变化而变化的,因为我们需要通过外部状态来标识对象,内部状态本身是多变的,如果外部状态会随着内部状态发生改变,会导致程序变得异常混乱。
享元模式还必须有一个工厂类,该类负责创建享元模式对象,同时需要记录下内存已经存在的享元模式对象用于之后的重复使用
具体我们通过例子来描述
案例
假如我们现在负责电脑维修业务,不同的电脑可能需要不同的维修工具,因此每次当需要我们没有的维修工具时,我们就需要去采购新的维修工具(创建新对象),但是如果我们仓库(内存)已经有了该维修工具(对象),那么就没必要再去采购新的维修工具了,可以直接从仓库(内存)中获取该维修工具(对象),同时现在的很多维修工具可以替换组件(外部状态),比如螺丝刀可以换头来应对不同型号的螺丝。
当然,这个例子可能并不是很恰当,因为在实际生活中维修工具本身要复杂的多,仅仅作为一个小示例。
代码实现
享元抽象类
@Data
public abstract class AbstractScrewdriver {
//外部状态组件
protected String module;
//内部状态,种类
protected String type;
public abstract void changeModule(String module);
}
享元实现类
public class Screwdriver extends AbstractScrewdriver{
@Override
public void changeModule(String module) {
this.module=module;
}
}
享元工厂
public class ScrewdriverFactory {
private static ScrewdriverFactory screwdriverFactory = new ScrewdriverFactory();
private final Hashtable<String, AbstractScrewdriver> screwdriver = new Hashtable<>();
private ScrewdriverFactory(){
}
public static ScrewdriverFactory getInstance()
{
return screwdriverFactory;
}
public AbstractScrewdriver getScrewdriver(String type)
{
AbstractScrewdriver abstractScrewdriver = screwdriver.get(type);
if(abstractScrewdriver==null){
Screwdriver screwdriver1=new Screwdriver();
screwdriver1.setType(type);
screwdriver.put(type,screwdriver1);
return screwdriver1;
}
return abstractScrewdriver;
}
}
总结
享元模式通过划分内部状态和外部状态的方式提取一组对象的共同特点,运用共享技术来避免大量对象创建而导致的内存和系统性能问题。
但是享元问题的直接使用具有线程安全问题,如果不加以任何的线程保护,在高并发情况下很有可能会出现对象的外部状态同时被多个线程改变而导致数据不一致问题,不建议在高并发环境下使用该模式