FlyWeight模式——設計模式學習筆記

FlyWeight模式

一 意圖

運用共享技術有效地支持大量細粒度的對象。

二 動機

      有些應用程序得益於在其整個設計過程中採用對象技術,但簡單化的實現代價極大。

使用面向對象的抽象化,可能會造成龐大的對象羣,造成空間的巨大消耗,而影響性能。

在文檔編輯器例子中如果一個字符對應一個對象,那麼一篇文檔所要容納的對象將是非常的龐大耗費大量的內存。

  而實際組成文檔的字符是有限的,是由這些字符不同的組合和排列得到的。

所以需要共享,將基本的字符進行共享,將使得字符對象變得有限。

Flyweight只存儲相應的字符代碼

這裏的關鍵概念是內部狀態外部狀態之間的區別。

  內部狀態存儲於flyweight中,它包含了獨立於flyweight場景的信息,這些信息使得flyweight可以被共享。

如字符代碼,字符大小……

  外部狀態取決於flyweight場景,並根據場景而變化,因此不可共享。用戶對象負責在必要的時候將外部狀態傳遞給flyweight。

如字符位置,字符顏色……


三 適用性及其結構

當以下情況都成立時使用Flyweight模式:

•一個應用程序使用了大量的對象。

• 完全由於使用大量的對象,造成很大的存儲開銷。

• 對象的大多數狀態都可變爲外部狀態。

• 如果刪除對象的外部狀態,那麼可以用相對較少的共享對象取代很多組對象。

• 應用程序不依賴於對象標識。由於Flyweight對象可以被共享,對於概念上明顯有別的對象,標識測試將返回真值。

結構:


description:

•Flyweight

— 描述一個接口,通過這個接口Flyweight可以接受並作用於外部狀態。

• ConcreteFlyweight

— 實現Flyweight接口, 併爲內部狀態( 如果有的話) 增加存儲空間。

ConcreteFlyweight對象必須是可共享的。它所存儲的狀態必須是內部的;即,它必

須獨立於Concrete Flyweight對象的場景。

• UnsharedConcreteFlyweight

— 並非所有的Flyweight子類都需要被共享。Flyweight接口使共享成爲可能,但它並不強制共享。在Flyweight對象結構的某些層次, UnsharedConcreteFlyweight對象通常

將ConcreteFlyweight對象作爲子節點(Row和Conum就是這樣)。

• FlyweightFactory

— 創建並管理Flyweight對象。

— 確保合理地共享Flyweight。當用戶請求一個Flyweight時,FlyweightFactory對象提供一個已創建的實例或者創建一個(如果不存在的話)。

• Client

— 維持一個對Flyweight的引用。

— 計算或存儲一個(多個)Flyweight的外部狀態。

 

Analysis:

  Flyweight執行時所需的狀態必定是內部的或外部的。內部狀態存儲於ConcreteFlyweight對象之中;

而外部對象則由C l i e n t對象存儲或計算。當用戶調用Flyweight對象的操作時,將該狀態傳遞給它。

• 用戶不應直接對ConcreteFlyweight類進行實例化,而只能從FlyweightFactory對象得到ConcreteFlyweight對象,

  這可以保證對它們適當地進行共享。

存儲節約由以下幾個因素決定:

• 因爲共享,實例總數減少的數目

• 對象內部狀態的平均數目

• 外部狀態是計算的還是存儲的

 

四 代碼實現

Note:

刪除外部狀態:該模式的可用性在很大程度上取決於是否容易識別外部狀態並將它從

共享對象中刪除

管理共享對象:引用計數和垃圾回收……

Example :象棋中的棋局中的棋子,任何棋局都是32個 棋子的不同組合。

1 Flyweight

Chess提供了外部狀態的設置

複製代碼
/*----------------------------------------------------------------*/
/* class Object */
/*----------------------------------------------------------------*/
class Object
{

};

/*----------------------------------------------------------------*/
/* class Chess */
/*----------------------------------------------------------------*/
class Chess: public Object
{
public:
Chess(){}
void setShape(int shape){}
void setSize(int size){}
void setHeight(int height){}
void setPos(int pos){}
virtual void draw()
{
cout<<"Chess draw"<<endl;
}
private:
int m_shape;
int m_size;
int m_height;
int m_pos;
};
複製代碼

 

CChess保存內部狀態

複製代碼
/*----------------------------------------------------------------*/
/* class CChess */
/*----------------------------------------------------------------*/
class CChess: public Chess
{
public:
CChess(int code)
{
m_code = code;
}
virtual void draw()
{
cout<<"CChess draw"<<endl;
}
private:
int m_code;
};
複製代碼


ChessFactory提供創建享元CChess的接口

複製代碼
/*----------------------------------------------------------------*/
/* class ChessFactory */
/*----------------------------------------------------------------*/
class ChessFactory: public Object
{
#define CHECSS_MAX_NUM (16)
#define CHESS_CODE_OFFSET (0x1000)
class ChessCodeMap
{
public:
int m_code;
CChess* m_chess;
};
public:
ChessFactory()
{
for (int i = 0; i < CHECSS_MAX_NUM; i++)
{
m_chessMap[i].m_chess = NULL;
m_chessMap[i].m_code = i;
}
}
CChess* createChess(int code)
{
for (int i = 0; i < CHECSS_MAX_NUM; i++)
{
if (m_chessMap[i].m_code == code)
{
if (m_chessMap[i].m_chess == NULL)
{
m_chessMap[i].m_chess = new CChess(code);
}

return m_chessMap[i].m_chess;
}
}

return NULL;
}
private:
ChessCodeMap m_chessMap[CHECSS_MAX_NUM];
};
複製代碼


Test

 

複製代碼
#include "flyweight.h"

int main()
{
ChessFactory* chessFc = new ChessFactory();
CChess* chess = chessFc->createChess(1);
chess->draw();

return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章