意图
运用共享技术来有効地支持大量细粒度对象的复用。
相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。
动机
在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源。
适用性
享元模式的应用场景如:
- 系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。
- 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。
- 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式。
结构
享元模式中存在以下两种状态:
- 内部状态,即不会随着环境的改变而改变的可共享部分;
- 外部状态,指随环境改变而改变的不可以共享的部分。享元模式的实现关键在于区分应用中的这两种状态,并将外部状态外部化。
享元模式的主要角色有:
- 抽象享元类(
Flyweight
):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。 - 具体享元类(
ConcreteFlyweight
):实现Flyweight
的接口。 - 非共享具体类(
UnshareConcreteFlyweight
):不参与共享的外部状态,它以参数的形式注入具体享元的相关方法中。 - 享元工厂类(
FlyweightFactory
):负责创建和管理具体享元类。
实现
// 享元接口(抽象享元类)
public interface Flyweight {
void operation(String state);
}
// 具体享元类
public class ConcreteFlyweight implements Flyweight {
// 内部状态,同一个享元对象的内部状态相同
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
System.out.println("创建具体享元对象,内部状态为" + intrinsicState);
}
//根据外部状态进行逻辑处理
@Override
public void operation(String extrinsicState) {
System.out.println("Object address: " + System.identityHashCode(this));
System.out.println("intrinsicState: " + intrinsicState);
System.out.println("extrinsicState: " + extrinsicState);
}
}
// 享元工厂类
public class FlyweightFactory {
private HashMap<String, Flyweight> cachePool = new HashMap<String, Flyweight>(16);
public Flyweight getFlyweight(String intrinsicState) {
Flyweight flyweight = null;
if (cachePool.containsKey(intrinsicState)) {
flyweight = cachePool.get(intrinsicState);
System.out.println("已存在享元对象直接获取,内部状态为" + intrinsicState);
} else {
flyweight = new ConcreteFlyweight(intrinsicState);
cachePool.put(intrinsicState, flyweight);
}
return flyweight;
}
}
// 测试客户端
public class TestClient {
public static void main(String[] args) {
FlyweightFactory factory=new FlyweightFactory();
// 只创建一次享元对象
Flyweight a0 = factory.getFlyweight("A");
Flyweight a1 = factory.getFlyweight("A");
a0.operation("a0");
a1.operation("a1");
}
}
已知应用
String常量池、数据库连接池、缓冲池等池技术的实现都应用了享元模式。
- Java中String字符串常量池
- Integer的享元模式解析
- 7种结构型模式之:享元模式(Flyweight)与数据库连接池的原理
- Apache commons-pool2-2.4.2源码学习笔记
相关模式
描述此模式和其他模式之间的关系。
参考资料
- 《
Head First
设计模式》 - 图说设计模式
- Java设计模式:23种设计模式全面解析(超级详细)