享元模式(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源碼學習筆記

相關模式

描述此模式和其他模式之間的關係。

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章