“享元”我们可以理解为共享元素,比如我们生活中的共享单车,共享充电宝,共享汽车,这样做的目的就是为了提高资源的复用,但对于共享的单车,充电宝等,它的拥有者和创建时间是不相同的,但是它核心的东西都是一致的,那么如果在我们的程序中有很多重复的对象,就会造成很大的内存开销
。
在享元模式中,它将元素分为两种状态
,一部分是内部状态
,例如共享单车,这部分是可以完全被共享的,但是对于共享单车的另一部分资源,比如拥有者和创建时间
,这部分信息是由客户端来决定的,谁此时使用,那么这部分的信息就是和谁有关的。
享元模式实现共享的核心是,我们不需要关心外部状态,将核心的资源包围起来共享出去,它内部信息都不会随着环境改变而改变,而外部状态,它会随着环境的改变而改变,这部分信息一定不是由我们自己来保存,共享对象一定不会保存这部分信息,这部分信息由客户端保存,客户端在用的时候,传入到享元对象内部,享元对象内部可以自己做一些处理,去使用或者展示他们,享元模式运用共享技术有效地支持大量细类度[细类度对象是指在某个类别下,具有不同属性或特征的对象,可以看作是对于一个类别的细分]的对象
,享元模式最典型的应用就是池技术,比如字符串常量池,数据库连接池,线程池等等,他们都是实现了对共享元素的有效利用,避免去创建大量重复的对象,有效地利用资源。
享元对象的内部状态和环境是没有任何关系的,那么外部状态如何传入呢?方法即为我们在定义享元的时候可以定义一些方法,用于将外部状态传入,这样就实现了一个享元对象既有内部状态,也可以接受外部状态
实例:
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号号充电宝
享元模式通过池技术,可以确保内存中相同或相似的对象只保留一份,可以大大节约系统资源,提高系统的性能,享元模式的外部状态相对独立,不会影响内部状态
,内外环境分离,使得享元对象可以在不同环境中被共享,因为它将状态区分出来,将外部状态由客户端指定,内部状态自己维护,这样使得它能够在不同环境中进行共享,它的缺点也很明显,因为我们要分离出内外状态,因此程序的逻辑性会比较复杂一点。外部状态都需要客户端传入,这也会影响它的运行时间
。