文書編輯器需顯示數萬字元、遊戲需渲染成千上萬樹木/子彈、報表系統產生海量格儲存格物件——若每個字元、樹木、格子都 new 一個獨立物件,記憶體將迅速耗盡。享元模式透過共享內部狀態、外部化可變狀態,以極少物件支撐龐大邏輯數量。
| 術語 | 說明 | 範例(文書編輯器) |
|---|---|---|
| 內部狀態 | 可共享、不隨環境改變 | 字元碼 'A'、字型家族 |
| 外部狀態 | 隨環境改變、不可共享 | 字元位置、字號、顏色、粗體 |
| 享元工廠 | 管理共享池、按鍵值取得/建立享元 | 字元碼 → CharacterFlyweight |

public abstract class CharacterFlyweight
{
// 外部狀態由呼叫端傳入
public abstract void Display(int position, string font, int size, ConsoleColor color);
}
public class ConcreteCharacter : CharacterFlyweight
{
private readonly char _symbol; // 內部狀態:唯讀、可共享
public ConcreteCharacter(char symbol) => _symbol = symbol;
public override void Display(int position, string font, int size, ConsoleColor color)
{
Console.ForegroundColor = color;
Console.WriteLine($"字元:'{_symbol}' 位置:{position} 字型:{font} 大小:{size} 顏色:{color}");
Console.ResetColor();
}
}
public class CharacterFactory
{
private readonly Dictionary _pool = new();
public CharacterFlyweight GetCharacter(char key)
{
if (!_pool.TryGetValue(key, out var flyweight))
{
flyweight = new ConcreteCharacter(key);
_pool[key] = flyweight;
Console.WriteLine($"[Factory] 建立新享元: '{key}',池大小: {_pool.Count}");
}
return flyweight;
}
public int PoolSize => _pool.Count;
}
class Program
{
static void Main()
{
var factory = new CharacterFactory();
string text = "HELLO WORLD"; // 模擬文檔內容
int pos = 0;
foreach (char c in text)
{
if (c == ' ') { pos++; continue; } // 空白略過
// 取得共享字元物件
var flyweight = factory.GetCharacter(char.ToUpper(c));
// 外部狀態:位置、字型、大小、顏色(這裡隨機示意)
flyweight.Display(pos++, "Consolas", 12, (ConsoleColor)(pos % 16));
}
Console.WriteLine($"\n文檔長度: {text.Length},實際物件數: {factory.PoolSize}");
Console.ReadKey();
}
}
[Factory] 建立新享元: 'H',池大小: 1
[Factory] 建立新享元: 'E',池大小: 2
[Factory] 建立新享元: 'L',池大小: 3
[Factory] 建立新享元: 'O',池大小: 4
[Factory] 建立新享元: 'W',池大小: 5
[Factory] 建立新享元: 'R',池大小: 6
[Factory] 建立新享元: 'D',池大小: 7
文檔長度: 11,實際物件數: 7
「HELLO WORLD」含 10 個非空白字元,但只有 7 個不重複字元,故僅建立 7 個物件即可服務所有顯示需求。
| 優點 | 缺點 |
|---|---|
| ✅ 大幅減少物件數量,降低記憶體占用 ✅ 內部狀態集中管理,易於維護 |
⚠️ 增加系統複雜度(需區分內/外部狀態) ⚠️ 執行時需查找/傳遞外部狀態,微增 CPU 開銷 ⚠️ 共享池本身佔用記憶體,物件數極少時得不償失 |
a == b 不重要)享元模式以「以少勝多」之勢,將不變的本質(內部狀態)共享,將變化的場景(外部狀態)外部化。在大量細粒度物件場景下,它是記憶體優化的利器;但切記:過早優化是萬惡之源,僅在記憶體分析確認瓶頸時再引入。