设计模式之享元模式
1.享元模式定义:是池技术重要的实现方式。使用共享对象可有效地支持大量细粒度的对象
目的:主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
享元模式为我们提出了两个要求:1.细粒度的对象 2.共享对象
对象的内部状态和外部状态:
内部状态:内部状态指的是对象中可以共享出来的信息。存贮在享元对象对象内部并且不会随对象内部改变而改变的对象。不必直接存储在具体的对象中,属于可以共享的部分
外部状态:外部对象是对象得以依赖的一个标记,是随环境的改变而改变。不可共享的状态,是一批对象的统一标识,是唯一的索引值
2.享元模式通用的类图:

类图说明:
FlyWeight:抽象享元角色
简单来说就是一个产品的抽象类,同时定义出对象的外部接口和内部状态的接口和实现
ConcreteFlyweight :具体享元角色
具体的一个角色,实现享元角色定义的业务。该角色需要注意的是内部状态处理与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态,这是绝对不允许的。
UnsharedConcreteFlyweight: 不可共享的享元角色
FlyweightFactory享元工厂:指责非常简单,是就是构造一个池容器。同时提供从池中获取对象的方法
3.享元模式通用代码
抽象享元角色:在抽象角色中,一般需要把外部状态和内部状态定义出来,避免子类随意扩展
public abstract class Flyweight {
// 内部状态
private String intrinsic;
// 外部状态 定义为final,防止无意修改了一下,造成池中混乱.在程序中,确认只需要一次赋值的属性,就设置为final.避免无意修改导致逻辑混乱,特别是session级别的常亮或者变量
protected final String Extrinsic;
// 要求享元角色必须接受外部状态
public Flyweight(String extrinsic) {
Extrinsic = extrinsic;
}
// 定义业务操作
public abstract void operate();
// 内部状态set/getter
public String getIntrinsic() {
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
具体享元角色
public class ConcreteFlyWeight extends Flyweight {
// 接受外部状态
public ConcreteFlyWeight(String extrinsic) {
super(extrinsic);
}
// 根据外部状态,进行逻辑操作
@Override
public void operate() {
System.out.println("执行操作=========>" + this.Extrinsic);
}
}
享元工厂
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);
System.out.println("直接从池中 取出数据==============>" + extrinsic);
} else {
// 根据外部状态撞见享元对象
flyweight = new ConcreteFlyWeight(extrinsic);
// 放置到池中
pool.put(extrinsic, flyweight);
System.out.println("池子中不存在数据,先创建,在放入池子中=============》" + extrinsic);
}
return flyweight;
}
}
测试结果:
public class TestFlyWeight {
@Test
public void test001() {
Flyweight flyweight1 = FlyWeightFactory.getFlyWeight("thread-1");
flyweight1.operate();
Flyweight flyweight2 = FlyWeightFactory.getFlyWeight("thread-2");
flyweight2.operate();
Flyweight flyweight3 = FlyWeightFactory.getFlyWeight("thread-3");
flyweight3.operate();
Flyweight flyweight4 = FlyWeightFactory.getFlyWeight("thread-1");
flyweight4.operate();
}
}
运行截图:

外部状态最好用java的基本类型作为标志,如String,int等,可以大幅度提升效率
4.享元模式的优缺点
优点:大大减少了对象的创建,降低了程序内存的占用,提高程序的性能
缺点:提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变
5.享元模式的使用场景
1.系统中存在大量的相似的对象
2.需要缓冲池的场景
6.注意事项:
1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。
2、这些类必须有一个工厂对象加以控制。
7.应用实例:
1.ResueExecutor对JDBC的statement对象进行了封装。当执行相同SQL语句的时候,直接从缓存中取出Statement对象进行复用,避免了频繁创建和销毁对象
2.数据库连接池
3.String.intern方法。如果String的对象池中有该类型的值,则直接返回对象池中的对象,如果没有则创建一个字符串保存在字符串缓存池里面
原文:https://www.cnblogs.com/yingxiaocao/p/13514674.html