# Flyweight 享元模式(輕量模式)
## 意圖
享元模式是一種結構型設計模式, 它摒棄了在每個對像中保存所有數據的方式, 通過共享多個對象所共有的相同狀態, 讓你能在有限的內存容量中載入更多對象。
## 說明
一個可能的例子是,後台商品管理介面有一個商品列表,每個商品都有一些共同的屬性,如分類、製造商、相同販賣店家等,也有一些不同的屬性,如庫存、銷量、評價等。如果每個商品都是一個完整的物件,那麼會佔用很多記憶體空間。但是如果將商品的共同屬性抽出來作為一個 flyweight 物件,並讓每個商品只保留不同的屬性,那麼就可以節省記憶體空間,並提高介面的效能。
### 內存狀態 與 外存狀態
#### 內部狀態 Intrinsic State
不會隨著環境改變而產生變化,所以內部狀態是可以共享的部分。
#### 外部狀態 Extrinsic State
會隨著環境改變而產生變化的部分,故這部分不可共享。
### 享元與不可變性
由於享元物件可在不同的情境中使用, 你必須確保其狀態不能被修改。 享元類別的狀態只能由建構函式的參數進行一次性初始化, 它不能對其他物件做結構上的修改,依照不可變性的設計原則可以提高物件的安全性、簡化性和效能。
## 結構
FlyweightFactoy: 負責建立及管理享元物件。當Client呼叫享元物件時,FlyweightFactory檢查是否存在符合要求的物件,存在則提供,不存在建立新的享元物件。
Flyweight: 為介面或抽象類別的接口,其中定義ConcreteFlyweight的方法,非享元的外部狀態以參數的形式通過方法傳入。
ConcreteFlyweight: 實現Flyweight。
UnsharedConcreteFlyweight: 稱作複合享元物件,不可共享。但可分解成多個單純享元物件,則可共享。複合享元物件可對多個單純享元物件設定相同的外部狀態。

## 適合應用場景
* 程式需要產生數量龐大的相似物件
* 這將耗盡大量的記憶體空間
* 物件中包含可抽取且能在多個物件間共享的重複狀態。
## 優點
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