享元模式(Flyweight Pattern)

意图

运用共享技术来有効地支持大量细粒度对象的复用。

相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。

动机

在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。创建那么多的对象将会耗费很多的系统资源,如果能把它们相同的部分提取出来共享,则能节省大量的系统资源。

适用性

享元模式的应用场景如:

  • 系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。
  • 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。
  • 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式。

结构

享元模式中存在以下两种状态:

  • 内部状态,即不会随着环境的改变而改变的可共享部分;
  • 外部状态,指随环境改变而改变的不可以共享的部分。享元模式的实现关键在于区分应用中的这两种状态,并将外部状态外部化。

享元模式的主要角色有:

  • 抽象享元类(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种设计模式全面解析(超级详细)

你可能感兴趣的:(面向对象)