1. 程式人生 > >設計模式總結之Flyweight Pattern(享元模式)

設計模式總結之Flyweight Pattern(享元模式)

目錄

建立型設計模式: 結構型設計模式: 行為型設計模式:

Flyweight Pattern(享元模式)

意圖

運用共享技術有效地支援大量細粒度的物件。

適用性

當以下所有的條件都滿足時,可以考慮使用享元模式:
* 一個應用程式使用了大量的物件。
* 完全由於使用大量的物件,造成很大的儲存開銷。
* 物件的大多數狀態都可變為外部狀態。
* 如果刪除物件的外部狀態,那麼可以用相對較少的共享物件取代很多組物件。
* 應用程式不依賴於物件標識。由於Flyweight物件可以被共享,對於概念上明顯有別的物件,標識測試將返回真值。


滿足以上的這些條件的系統可以使用享元物件。


最後,使用享元模式需要維護一個記錄了系統已有的所有享元的表,而這需要耗費資源。因此,應當在有足夠多的享元例項可供共享時才值得使用享元模式。


注意要點:
  根據我們的經驗,當要將一個物件進行共享時,就需要考慮到物件的狀態問題了;不同的客戶端獲得共享的物件之後,可能會修改共享物件的某些狀態;大家都修改了共享物件的狀態,那麼就會出現物件狀態的紊亂。對於享元模式,在實現時一定要考慮到共享物件的狀態問題。那麼享元模式是如何實現的呢?
  在享元模式中,有兩個非常重要的概念:內部狀態(intrinsicState)和外部狀態(extrinsicState)。
  內部狀態儲存於flyweight中,它包含了獨立於flyweight場景的資訊,這些資訊使得flyweight可以被共享。而外部狀態取決於flyweight場景,並根據場景而變化,因此不可共享。使用者物件負責在必要的時候將外部狀態傳遞給flyweight。
  flyweight執行時所需的狀態必定是內部的或外部的。內部狀態儲存於ConcreteFlyweight物件之中;而外部物件則由 Client物件儲存或計算。當用戶呼叫flyweight物件的操作時,將該狀態傳遞給它。同時,使用者不應該直接對ConcreteFlyweight 類進行例項化,而只能從FlyweightFactory物件得到ConcreteFlyweight物件,這可以保證對它們適當地進行共享;由於共享一 個例項,所以在建立這個例項時,就可以考慮使用單例模式來進行實現。
  享元模式的工廠類維護了一個例項列表,這個列表中儲存了所有的共享例項;當用戶從享元模式的工廠類請求共享物件時,首先查詢這個例項表,如果不存在對應例項,則建立一個;如果存在,則直接返回對應的例項。


結構



Flyweight:描述一個介面,通過這個介面flyweight可以接受並作用於外部狀態;
ConcreteFlyweight:實現Flyweight介面,併為定義了一些內部狀態,ConcreteFlyweight物件必須是可共享的;同時,它所儲存的狀態必須是內部的;即,它必須獨立於ConcreteFlyweight物件的場景;
UnsharedConcreteFlyweight:並非所有的Flyweight子類都需要被共享。Flyweight介面使共享成為可能,但它並不強制共享。
FlyweightFactory:建立並管理flyweight物件。它需要確保合理地共享flyweight;當用戶請求一個flyweight時,FlyweightFactory物件提供一個已建立的例項,如果請求的例項不存在的情況下,就新建立一個例項;
Client:維持一個對flyweight的引用;同時,它需要計算或儲存flyweight的外部狀態。


如何共享了Flyweight,如下圖:




例子



注:可共享——>可以理解為可以複用的。
不可共享——>可以理解為不需要複用,不可複用的。


優缺點

> 優點:
享元模式可以避免大量非常相似物件的開銷。在程式設計時,有時需要生成大量細粒度的類例項來表示資料。如果能發現這些例項資料除了幾個引數外基本都是相同的,使用享元模式就可以大幅度地減少物件的數量。


> 缺點:
1)享元模式使得系統更加複雜。為了使物件可以共享,需要將一些狀態外部化,這使得程式的邏輯複雜化。
2)享元模式將享元物件的狀態外部化,而讀取外部狀態使得執行時間稍微變長。