享元 (Flyweight)

★★★★★Studied

FromDesign Patterns (GoF)大話設計模式

📚 From the Books

享元 (Flyweight)ConceptStructural

當要建立大量相似物件時,把可共享的不可變狀態(intrinsic)抽出來共用,把每個情境才不同的狀態(extrinsic)由外部傳入,藉此大幅省記憶體。

🧠 When to Use

TIP

訊號:你要產生海量物件(文字每個字元、地圖每塊磚、粒子系統),而它們大部分欄位其實長得一樣。

⚖️ Structure & Variants

經典版 — 共享 intrinsic、外傳 extrinsic
// Flyweight:只存可共享、不可變的 intrinsic 狀態(字形外觀)
class Glyph(val char: Char, val font: Font)

// Factory:同 key 回傳同一個共享實例
object GlyphFactory {
    private val pool = HashMap<Pair<Char, Font>, Glyph>()
    fun get(c: Char, f: Font): Glyph = pool.getOrPut(c to f) { Glyph(c, f) }
}

// extrinsic 狀態(位置)由呼叫端傳入,不存進 Glyph
fun drawAt(g: Glyph, x: Int, y: Int) { /* render g at (x, y) */ }

val a = GlyphFactory.get('a', Font.SERIF)   // 整份文件的所有 'a' 共用同一個
  • 一份十萬字的文件,只需數十個 Glyph 實例。
intrinsic vs extrinsic 的界線
  • Intrinsic:與情境無關、可共享、必須不可變(字元、字型、磚塊貼圖)。
  • Extrinsic:每次使用才決定、由外部傳入(座標、旋轉、當前狀態)。
  • 界線畫錯(把該外傳的塞進共享物件)會破壞共享、甚至引發競態。
和 Singleton / Composite 的關係
  • Singleton 都靠共享實例,但 Flyweight 是一群有限的共享物件、由 factory 池管理。
  • 樹狀結構(Composite)裡的葉子常用 Flyweight 來省記憶體。

⚠️ Misuse & Anti-patterns

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading