享元模式的定义
享元模式是池技术的重要实现方式,其定义如下:使用共享对象可以有效地支持大量细粒度的对象
享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象,不可变对象是指:一旦通过构造函数初始化完成之后,它的状态(对象的成员变量或者属性)就不会发生修改了,所以不可变对象不可以暴露任何set()等修改内部状态的方法
享元模式的实现其实很简单,主要是通过工厂模式,在工厂类中,通过一个Map来缓存已经创建过的享元对象
享元模式通用类图
-
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;
}
}
享元模式优缺点
享元模式减少了应用程序创建的对象,降低了程序内存的占用,增强了程序的性能,但是它也提高了程序的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随着内部状态的变化而变化,否则会导致系统的逻辑混乱
享元模式的使用场景
- 系统中存在大量相似的对象
- 细粒度对象都具备较为接近的外部状态,而且内部状态与环境无关
- 需要缓冲池的场景