# Flyweight 享元模式(輕量模式) ## 意圖 享元模式是一種結構型設計模式, 它摒棄了在每個對像中保存所有數據的方式, 通過共享多個對象所共有的相同狀態, 讓你能在有限的內存容量中載入更多對象。 ## 說明 一個可能的例子是,後台商品管理介面有一個商品列表,每個商品都有一些共同的屬性,如分類、製造商、相同販賣店家等,也有一些不同的屬性,如庫存、銷量、評價等。如果每個商品都是一個完整的物件,那麼會佔用很多記憶體空間。但是如果將商品的共同屬性抽出來作為一個 flyweight 物件,並讓每個商品只保留不同的屬性,那麼就可以節省記憶體空間,並提高介面的效能。 ### 內存狀態 與 外存狀態 #### 內部狀態 Intrinsic State 不會隨著環境改變而產生變化,所以內部狀態是可以共享的部分。 #### 外部狀態 Extrinsic State 會隨著環境改變而產生變化的部分,故這部分不可共享。 ### 享元與不可變性 由於享元物件可在不同的情境中使用, 你必須確保其狀態不能被修改。 享元類別的狀態只能由建構函式的參數進行一次性初始化, 它不能對其他物件做結構上的修改,依照不可變性的設計原則可以提高物件的安全性、簡化性和效能。 ## 結構 FlyweightFactoy: 負責建立及管理享元物件。當Client呼叫享元物件時,FlyweightFactory檢查是否存在符合要求的物件,存在則提供,不存在建立新的享元物件。 Flyweight: 為介面或抽象類別的接口,其中定義ConcreteFlyweight的方法,非享元的外部狀態以參數的形式通過方法傳入。 ConcreteFlyweight: 實現Flyweight。 UnsharedConcreteFlyweight: 稱作複合享元物件,不可共享。但可分解成多個單純享元物件,則可共享。複合享元物件可對多個單純享元物件設定相同的外部狀態。 ![](https://hackmd.io/_uploads/r10v-xIEn.png) ## 適合應用場景 * 程式需要產生數量龐大的相似物件 * 這將耗盡大量的記憶體空間 * 物件中包含可抽取且能在多個物件間共享的重複狀態。 ## 優點 1. 降低內存中物件的數量,以減少記憶體使用,且物件可被集中於一處來管理。 1. 外部狀態獨立,可使享元對象在不同環境被共享。 ## 缺點 1. 需要分離出內部狀態和外部狀態,使得系統變複雜。 1. 為了使對象可以共享,享元模式需要將享元對象的狀態外部化,讀取外部狀態的時間變長(犧牲執行速度來換取記憶體)。 ## 小節 * 可以使用享元模式實現組合模式樹的共享節點以節省記憶體。 * 如果你能將物件的所有共享狀態簡化為一個享元物件,那麼享元就和單例模式類似了。 但這兩個模式有兩個根本性的不同。 1. 只會有一個單例實體, 但是享元類別可以有多個實體, 各實體的內在狀態也可以不同。 1. 單例物件可以是可變的。 享元物件是不可變的。 ## 資料來源 https://refactoringguru.cn/design-patterns/flyweight https://hackmd.io/@110-OO/Bk14LHJEY https://note.dolyw.com/design/11-Flyweight-Pattern.html#_1-%E4%BB%8B%E7%BB%8D