面向物件雖解決抽象問題,但大量細粒度物件會導致執行期記憶體壓力。享元模式透過共享技術支援大量細粒度物件,本文以字元處理為例,展示從朴素設計到享元模式的重構演進,深入剖析內部/外部狀態分離、享元工廠、單例工廠等關鍵實作細節。
意圖:運用共享技術有效支援大量細粒度物件。(GoF)
結構圖:

撥號音發生器、鈴聲發生器、接收器為所有用戶共享,用戶無感知即享用資源:

public abstract class Charactor {
protected char _symbol; protected int _width, _height, _ascent, _descent, _pointSize;
public abstract void Display();
}
public class CharactorA : Charactor { /* 固定屬性 */ }
public class CharactorB : Charactor { ... }
public class CharactorC : Charactor { ... }
文檔中上萬字元 → 上萬物件 → 記憶體耗盡。
分析發現:字元符號、寬高等為內部狀態 (可共享);字體大小 pointSize 為外部狀態 (不可共享)。移除 pointSize 使物件可共享:

單一職責:物件不應自管建立邏輯。CharactorFactory 管理共用池:
public class CharactorFactory {
private Hashtable _pool = new Hashtable();
public CharactorFactory() {
_pool["A"] = new CharactorA(); _pool["B"] = new CharactorB(); _pool["C"] = new CharactorC();
}
public Charactor GetCharactor(string key) {
if (!_pool.ContainsKey(key)) {
switch(key) { case "A": _pool[key]=new CharactorA(); break; ... }
}
return (Charactor)_pool[key];
}
}
嘗試 1:客戶端自行設定外部狀態 → 重複邏輯、破壞封裝。
嘗試 2 (正解):外部狀態透過方法參數傳入,保持封裝:
public abstract class Charactor {
public abstract void SetPointSize(int size);
public abstract void Display();
}
public class CharactorA : Charactor {
private int _pointSize;
public override void SetPointSize(int size) => _pointSize = size;
public override void Display() => Console.WriteLine($"{_symbol} pointsize:{_pointSize}");
}
用戶端調用:
var factory = new CharactorFactory();
var ca = (CharactorA)factory.GetCharactor("A");
ca.SetPointSize(12); ca.Display();
若建立多個工廠實例,共享池失效。工廠必須為單例:
public class CharactorFactory {
private static CharactorFactory _instance;
private Hashtable _pool = new Hashtable();
private CharactorFactory() { /* 初始化池 */ }
public static CharactorFactory Instance => _instance ?? (_instance = new CharactorFactory());
public Charactor GetCharactor(string key) { ... }
}

.NET string 內建享元機制:相同字面值共享同一物件實例。
string s1 = "abcd"; string s2 = "abcd";
Console.WriteLine(Object.ReferenceEquals(s1, s2)); // True
string s3 = "ab"; s3 += "cd";
Console.WriteLine(Object.ReferenceEquals(s1, s3)); // False (運算時產生新物件)
享元模式解決細粒度物件記憶體壓力,屬底層效能優化手段,實務較少見但關鍵時極具威力。掌握內外部狀態分離與工廠單例管理,即掌握享元精髓。