享元模式
以共享的方式高效地支持大量的細粒度對象
享元對象的狀態
:內蘊狀態(Internal State)內蘊狀態存儲在享元對象內部且不會隨環境改變而改變
因此內蘊狀態並可以共享
:外蘊狀態(External State)
外蘊狀態是隨環境改變而改變的
不可以共享的狀態
享元對象的外蘊狀態必須由客戶端保存
並在享元對象被創建之後
在需要使用的時候再傳入到享元對象內部
外蘊狀態與內蘊狀態是相互獨立的
享元模式的應用條件
: 一個系統有大量的對象
:這些對象耗費大量的內存
:這些對象的狀態中的大部分都可以外部化
:這些對象可以按照內蘊狀態分成很多的組
當把外蘊對象從對象中剔除時
每一個組都可以僅用一個對象代替
:軟件系統不依賴於這些對象的身份
換言之
這些對象可以是不可分辨的
NET的享元模式
NET中的String類型就是運用了享元模式……NET中如果第一次創建了一個字符串對象s
下次再創建相同的字符串s
時只是把它的引用指向s
所引用的具體對象
這就實現了相同字符串在內存中的共享
下面的程序來演示s
和s
的引
用是否一致
輸出的結果為True
string s
=
測試字符串一
;
string s
=
測試字符串一
;
Console
WriteLine(Object
ReferenceEquals(s
s
))
注意
如果再有一個字符串s
它的初始值為
測試字符串
再對它進行操作s
= s
+
一
這時雖然s
和s
的值相同
但是它們的引用是不同的
享元模式的分類
單純享元模式
復合享元模式
第一
單純享元模式
單純享元模式結構圖
單純享元模式構成說明
>:抽象享元(Flyweight)角色
此角色是所有的具體享元類的超類
為這些類規定出需要實現的公共接口
那些需要外蘊狀態(External State)的操作可以通過調用商業方法以參數形式傳入
/// <summary>
///
Flyweight
/// </summary>
abstract class Flyweight
{
// Methods
/// <summary>
/// 抽象享元對象的商業方法
/// </summary>
/// <param name=
extrinsicstate
>外蘊狀態</param>
abstract public void Operation(int extrinsicstate)
}
>:具體享元(ConcreteFlyweight)角色
實現抽象享元角色所規定的接口
如果有內蘊狀態的話
必須負責為內蘊狀態提供存儲空間
享元對象的內蘊狀態必須與對象所處的周圍環境無關
從而使得享元對象可以在系統內共享的
/// <summary>
///
ConcreteFlyweight
/// </summary>
class ConcreteFlyweight : Flyweight
{
private string intrinsicstate =
A
;
// Methods
override public void Operation(int extrinsicstate)
{
Console
WriteLine(
ConcreteFlyweight: intrinsicstate {
}
extrinsicstate {
}
intrinsicstate
extrinsicstate)
}
}
>:享元工廠(FlyweightFactory)角色
本角色負責創建和管理享元角色
本角色必須保證享元對象可以被系統適當地共享
當一個客戶端對象調用一個享元對象的時候
享元工廠角色會檢查系統中是否已經有一個復合要求的享元對象
如果已經有了
享元工廠角色就應當提供這個已有的享元對象
如果系統中沒有一個適當的享元對象的話
享元工廠角色就應當創建一個合適的享元對象
注意
客戶端不可以直接實例化享元類
必須通過享元工廠類來創建
因為享元工廠類在系統中只能有一個
所以可以結合單例模式來改善
當客戶端需要單純享元對象時
需要調用享元工廠的Singleton()方法
此時工廠會取得所有的單純享元對象
然後傳入所需的單純享元對象的內蘊狀態
工廠方法負責產生所需要的享元對象
/// <summary>
///
FlyweightFactory
/// </summary>
class FlyweightFactory
{
// Fields
private Dictionary<string
Flyweight> flyweights = new Dictionary<string
Flyweight>()
private static readonly FlyweightFactory instance = new FlyweightFactory()
/// <summary>
/// Constructors
/// </summary>
private FlyweightFactory()
{
}
// Methods
/// <summary>
/// 從享元工廠中生產出一個具體的享元對象
/// </summary>
/// <param name=
key
>內蘊狀態</param>
/// <returns></returns>
public Flyweight GetFlyweight(string key)
{
return ((Flyweight)flyweights[key])
}
/// <summary>
/// 享元工廠單例方法
/// </summary>
/// <returns></returns>
public static FlyweightFactory Singleton()
{
return FlyweightFactory
instance;
}
/// <summary>
/// 向享元工廠對象增加一個享元對象
/// </summary>
/// <param name=
sKey
>內蘊狀態</param>
/// <param name=
_Flyweight
>具體享元對象</param>
public void AddFlyweight(string sKey
Flyweight _Flyweight)
{
flyweights
Add(sKey
_Flyweight)
}
public Flyweight factory(string sKey)
{
if (flyweights
ContainsKey(sKey))
{
return this
GetFlyweight(sKey)
}
else
{
this
AddFlyweight(sKey
new ConcreteFlyweight())
return this
GetFlyweight(sKey)
}
}
}
>:客戶端(Client)角色
需要維護一個對所有享元對象的引用
需要自行存儲所有享元對象外蘊狀態
// 初始化外蘊狀態值
int extrinsicstate =
;
//享元工廠對象使用單例
FlyweightFactory f = FlyweightFactory
Singleton () ;
//調用過程
//向享元工廠對象請求一個內蘊狀態為
X
的單純享元對象
Flyweight fx = f
factory(
X
)
//調用X的商業方法
X的外蘊狀態值為
fx
Operation(
extrinsicstate)
Flyweight fy = f
factory(
Y
)
fy
Operation(
extrinsicstate)
Flyweight fz = f
factory(
Z
)
fz
Operation(
extrinsicstate)
第二
復合享元模式
復合享元模式結構圖
結構對象說明
:抽象享元角色
此角色是所有的具體享元類的超類
為這些類規定出需要實現的公共接口
那些需要外蘊狀態(External State)的操作可以通過方法的參數傳入
抽象享元的接口使得享元變得可能
但是並不強制子類實行共享
因此並非所有的享元對象都是可以共享的
:具體享元(ConcreteFlyweight)角色
實現抽象享元角色所規定的接口
如果有內蘊狀態的話
必須負責為內蘊狀態提供存儲空間
享元對象的內蘊狀態必須與對象所處的周圍環境無關
從而使得享元對象可以在系統內共享
有時候具體享元角色又叫做單純具體享元角色
因為復合享元角色是由單純具體享元角色通過復合而成的
:復合享元(UnsharableFlyweight)角色
復合享元角色所代表的對象是不可以共享的
但是一個復合享元對象可以分解成為多個本身是單純享元對象的組合
復合享元角色又稱做不可共享的享元對象
:享元工廠(FlyweightFactoiy)角色
本角色負責創建和管理享元角色
本角色必須保證享元對象可以被系統適當地共享
當一個客戶端對象請求一個享元對象的時候
享元工廠角色需要檢查系統中是否已經有一個符合要求的享元對象
如果已經有了
享元工廠角色就應當提供這個已有的享元對象
如果系統中沒有一個適當的享元對象的話
享元工廠角色就應當創建一個新的合適的享元對象
:客戶端(Client)角色
本角色還需要自行存儲所有享元對象的外蘊狀態
享元模式的優點
大幅度地降低內存中對象的數量
享元模式的缺點
:享元模式使得系統更加復雜
為了使對象可以共享
需要將一些狀態外部化
這使得程序的邏輯復雜化
:享元模式將享元對象的狀態外部化
而讀取外部狀態使得運行時間稍微變長
總結
享元模式一般是解決系統性能問題的
所以經常用於底層開發
在項目開發中並不常用
From:http://tw.wingwit.com/Article/program/net/201311/12438.html