“享元”我们可以理解为共享元素,比如我们生活中的共享单车,共享充电宝,共享汽车,这样做的目的就是为了提高资源的复用,但对于共享的单车,充电宝等,它的拥有者和创建时间是不相同的,但是它核心的东西都是一致的,那么如果在我们的程序中有很多重复的对象,就会造成很大的内存开销。
在享元模式中,它将元素分为两种状态,一部分是内部状态,例如共享单车,这部分是可以完全被共享的,但是对于共享单车的另一部分资源,比如拥有者和创建时间,这部分信息是由客户端来决定的,谁此时使用,那么这部分的信息就是和谁有关的。
享元模式实现共享的核心是,我们不需要关心外部状态,将核心的资源包围起来共享出去,它内部信息都不会随着环境改变而改变,而外部状态,它会随着环境的改变而改变,这部分信息一定不是由我们自己来保存,共享对象一定不会保存这部分信息,这部分信息由客户端保存,客户端在用的时候,传入到享元对象内部,享元对象内部可以自己做一些处理,去使用或者展示他们,享元模式运用共享技术有效地支持大量细类度[细类度对象是指在某个类别下,具有不同属性或特征的对象,可以看作是对于一个类别的细分]的对象,享元模式最典型的应用就是池技术,比如字符串常量池,数据库连接池,线程池等等,他们都是实现了对共享元素的有效利用,避免去创建大量重复的对象,有效地利用资源。
享元对象的内部状态和环境是没有任何关系的,那么外部状态如何传入呢?方法即为我们在定义享元的时候可以定义一些方法,用于将外部状态传入,这样就实现了一个享元对象既有内部状态,也可以接受外部状态
实例:
1:创建抽象的享元对象
package com.wjr.xiangyaunModel.shared_power_bank; abstract class PowerBankWeight {//抽象的享元对象 protected int state=0;//0表示未使用,1表示使用 abstract void getPowerBank(String username); abstract void backPowerBank(); }
2:创建具体的享元对象
package com.wjr.xiangyaunModel.shared_power_bank; public class LvPowerBankWeight extends PowerBankWeight{ protected String id; public LvPowerBankWeight(String id) { this.id=id; } @Override void getPowerBank(String userName) { state=1;//表示当前为使用状态 System.out.println(userName+"正在使用"+id+"号充电宝"); } @Override void backPowerBank() { state=0;//表示当前为未使用状态 } }
3:创建享元对象工厂
package com.wjr.xiangyaunModel.shared_power_bank; import java.util.HashSet; public class PowerBankFlyWeightFactory { private static PowerBankFlyWeightFactory powerBankFlyWeightFactory=new PowerBankFlyWeightFactory(); HashSet<LvPowerBankWeight> pool=new HashSet<>();//享元对象池--数据结构不唯一,也可选择TreeSet,如何进行选择需要我们根据需求进行分析 public static PowerBankFlyWeightFactory getPowerBankFlyWeightFactory(){ return powerBankFlyWeightFactory; } public PowerBankFlyWeightFactory() { //表示享元对象的数量为3 for(int i=0;i<3;i++){ pool.add(new LvPowerBankWeight(i+"号")); } } public LvPowerBankWeight getPowerBank(){ for(LvPowerBankWeight lvPowerBankWeight:pool){ if(lvPowerBankWeight.state==0){ return lvPowerBankWeight; } } return null; } }
package com.wjr.xiangyaunModel.shared_power_bank; public class FlyWeightPattern { public static void main(String[] args) { LvPowerBankWeight lvPowerBankWeight1=PowerBankFlyWeightFactory.getPowerBankFlyWeightFactory().getPowerBank(); lvPowerBankWeight1.getPowerBank("小学牲"); lvPowerBankWeight1.backPowerBank(); LvPowerBankWeight lvPowerBankWeight2=PowerBankFlyWeightFactory.getPowerBankFlyWeightFactory().getPowerBank(); lvPowerBankWeight2.getPowerBank("中学牲"); // lvPowerBankWeight2.backPowerBank(); LvPowerBankWeight lvPowerBankWeight3=PowerBankFlyWeightFactory.getPowerBankFlyWeightFactory().getPowerBank(); lvPowerBankWeight3.getPowerBank("大学牲"); // lvPowerBankWeight3.backPowerBank(); LvPowerBankWeight lvPowerBankWeight4=PowerBankFlyWeightFactory.getPowerBankFlyWeightFactory().getPowerBank(); lvPowerBankWeight4.getPowerBank("打工人"); lvPowerBankWeight4.backPowerBank(); } }
输出如下所示:
小学牲正在使用1号号充电宝 中学牲正在使用1号号充电宝 大学牲正在使用2号号充电宝 打工人正在使用0号号充电宝
享元模式通过池技术,可以确保内存中相同或相似的对象只保留一份,可以大大节约系统资源,提高系统的性能,享元模式的外部状态相对独立,不会影响内部状态,内外环境分离,使得享元对象可以在不同环境中被共享,因为它将状态区分出来,将外部状态由客户端指定,内部状态自己维护,这样使得它能够在不同环境中进行共享,它的缺点也很明显,因为我们要分离出内外状态,因此程序的逻辑性会比较复杂一点。外部状态都需要客户端传入,这也会影响它的运行时间。