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;
}