在物件導向程式設計過程中,有時會面臨要建立大量相同或相似物件例項的問題。建立那麼多的物件將會耗費很多的系統資源,它是系統效能提高的乙個瓶頸。
例如,圍棋和五子棋中的黑白棋子,影象中的座標點或顏色,區域網中的路由器、交換機和集線器,教室裡的桌子和凳子等。這些物件有很多相似的地方,如果能把它們相同的部分提取出來共享,則能節省大量的系統資源,這就是享元模式的產生背景。
享元(flyweight)模式的定義:運用共享技術來有效地支援大量細粒度物件的復用。它通過共享已經存在的物件來大幅度減少需要建立的物件數量、避免大量相似類的開銷,從而提高系統資源的利用率。
享元模式的主要優點是:相同物件只要儲存乙份,這降低了系統中物件的數量,從而降低了系統中細粒度物件給記憶體帶來的壓力。
其主要缺點是:
享元模式的定義提出了兩個要求,細粒度和共享物件。因為要求細粒度,所以不可避免地會使物件數量多且性質相近,此時我們就將這些物件的資訊分為兩個部分:內部狀態和外部狀態。
比如,連線池中的連線物件,儲存在連線物件中的使用者名稱、密碼、連線url等資訊,在建立物件的時候就設定好了,不會隨環境的改變而改變,這些為內部狀態。而當每個連線要被**利用時,我們需要將它標記為可用狀態,這些為外部狀態。
享元模式的本質是快取共享物件,降低記憶體消耗。
模式的結構
享元模式的主要角色有如下。
下圖是享元模式的結構圖,其中:
享元模式的實現**如下:
#include #include #include using namespace std;
// 非享元角色
class unsharedconcreteflyweight
string getinfo()
void setinfo(string info)
private:
string info;
};// 抽象享元角色
class flyweight
virtual string getintrinsicstate() {}
};// 具體享元角色
class concreteflyweight: public flyweight
void operation(unsharedconcreteflyweight *outstate)
string getintrinsicstate()
protected:
string key;
};// 享元工廠角色
class flyweightfactory
flyweight* getflyweight(const string& key)
}flyweight* fn = new concreteflyweight(key);
_fly.push_back(fn);
// 返回具體享元
return fn;
}private:
vector_fly;
};int main()
程式執行結果如下:
具體享元a被建立!
具體享元a已經存在,被成功獲取!
具體享元a已經存在,被成功獲取!
具體享元b被建立!
具體享元b已經存在,被成功獲取!
具體享元a被呼叫,非享元資訊是:第1次呼叫a。
具體享元a被呼叫,非享元資訊是:第2次呼叫a。
具體享元a被呼叫,非享元資訊是:第3次呼叫a。
具體享元b被呼叫,非享元資訊是:第1次呼叫b。
具體享元b被呼叫,非享元資訊是:第2次呼叫b。
**說明:享元模式在實現過程中主要是要為共享物件提供乙個存放的"倉庫"(物件池),這裡是通過 c++ stl 中 vector 容器。
另外應該注意的就是對物件"倉庫"(物件池)的管理策略(查詢、插入等),這裡是通過直接的順序遍歷實現的,當然我們可以使用其他更加有效的索引策略,例如 hash 表的管理策略,當然這些細節已經不是享元模式本身要處理的了。
五子棋同圍棋一樣,包含多個「黑」或「白」顏色的棋子,所以用享元模式比較好。
下圖所示是其結構圖:
程式**如下:
#include #include #include #include using namespace std;
// 非享元角色:棋子所下的位置座標
class point
int getx()
int gety()
private:
int x;
int y;
};// 抽象享元角色:棋子
class chesspieces // 下子
protected:
string color;
};// 具體享元角色:白子
class whitepieces: public chesspieces
};// 具體享元角色:黑子
class blackpieces: public chesspieces
};// 享元工廠角色
class flyweightfactory
// 返回抽象享元角色:棋子
chesspieces* getchesspieces(const string& type)
else if (type == "b") else
}private:
vectorvecfly;
};int main()
輸出如下:
downpieces: black 10,20
downpieces: black 30,40
downpieces: white 50,60
downpieces: white 70,80
當系統中多處需要同一組資訊時,可以把這些資訊封裝到乙個物件中,然後對該物件進行快取,這樣,乙個物件就可以提供給多出需要使用的地方,避免大量同一物件的多次建立,降低大量記憶體空間的消耗。
享元模式其實是工廠方法模式的乙個改進機制,享元模式同樣要求建立乙個或一組物件,並且就是通過工廠方法模式生成物件的,只不過享元模式為工廠方法模式增加了快取這一功能。
前面分析了享元模式的結構與特點,下面分析它適用的應用場景。享元模式是通過減少記憶體中物件的數量來節省記憶體空間的,所以以下幾種情形適合採用享元模式。
在前面介紹的享元模式中,其結構圖通常包含可以共享的部分和不可以共享的部分。在實際使用過程中,有時候會稍加改變,即存在兩種特殊的享元模式:單純享元模式和復合享元模式,下面分別對它們進行簡單介紹:
參考:
知乎 - 如何學習設計模式? 熱門回答
享元模式(詳解版)
c++享元模式
菜鳥教程 - 設計模式篇
結構型模式(6) 享元模式
運用共享技術來有効地支援大量細粒度物件的復用。乙個類它可能生成好多物件,但這些物件根據屬性值的不同一共分成n類,每種型別中屬性值都是一樣的。在這種情況下,如果建立好多物件,那麼這些物件中很多屬性值都是重複的,從而造成了大量的記憶體浪費。而享元模式能夠解決重複物件的記憶體浪費的問題。享元模式使用乙個工...
設計模式 結構型模式 享元模式
圍棋棋子類 抽象享元類 abstract class igochessman 黑色棋子類 具體享元類 class blackigochessman extends igochessman 白色棋子類 具體享元類 class whiteigochessman extends igochessman 圍...
設計模式 結構型模式 享元模式
享元模式 使用同乙個物件,有一些物件不想重複建立,想使用乙個 與單例的區別 建立物件是自身控制,還是交由乙個工廠控制 string字串的記憶體分配使用了享元模式 字元父類 public abstract class baseword l類 public class l baseword public...