意圖
運用共享技術來有効地支持大量細粒度對象的複用。
相同對象只要保存一份,這降低了系統中對象的數量,從而降低了系統中細粒度對象給內存帶來的壓力。
動機
在面向對象程序設計過程中,有時會面臨要創建大量相同或相似對象實例的問題。創建那麼多的對象將會耗費很多的系統資源,如果能把它們相同的部分提取出來共享,則能節省大量的系統資源。
適用性
享元模式的應用場景如:
- 系統中存在大量相同或相似的對象,這些對象耗費大量的內存資源。
- 大部分的對象可以按照內部狀態進行分組,且可將不同部分外部化,這樣每一個組只需保存一個內部狀態。
- 由於享元模式需要額外維護一個保存享元的數據結構,所以應當在有足夠多的享元實例時才值得使用享元模式。
結構
享元模式中存在以下兩種狀態:
- 內部狀態,即不會隨着環境的改變而改變的可共享部分;
- 外部狀態,指隨環境改變而改變的不可以共享的部分。享元模式的實現關鍵在於區分應用中的這兩種狀態,並將外部狀態外部化。
享元模式的主要角色有:
- 抽象享元類(
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種設計模式全面解析(超級詳細)