大話設計模式 —— 第二十六章《享元模式》C++ 代碼實現

目錄

定義

優點

缺點

應用場景


在面向對象程序設計過程中,有時會面臨要創建大量相同或相似對象實例的問題。創建那麼多的對象將會耗費很多的系統資源,它是系統性能提高的一個瓶頸。例如,圍棋和五子棋中的黑白棋子,圖像中的座標點或顏色,局域網中的路由器、交換機和集線器,教室裏的桌子和凳子等。這些對象有很多相似的地方,如果能把它們相同的部分提取出來共享,則能節省大量的系統資源。

也就是說在一個系統中如果有多個相同的對象,那麼只共享一份就可以了,不必每個都去實例化一個對象。比如說一個文本系統,每個字母定一個對象,那麼大小寫字母一共就是52個,那麼就要定義52個對象。如果有一個1M的文本,那麼字母是何其的多,如果每個字母都定義一個對象那麼內存早就爆了。那麼如果要是每個字母都共享一個對象,那麼就大大節約了資源。
  在Flyweight模式中,由於要產生各種各樣的對象,所以在Flyweight(享元)模式中常出現Factory模式。Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個對象存儲池(Flyweight Pool)來存放內部狀態的對象。Flyweight模式是一個提高程序效率和性能的模式,會大大加快程序的運行速度。


定義


享元模式是一種結構型設計模式。該模式主要是通過將對象的粒度細分,從而減少創建大量對象所佔的內存。定義爲:

  • 定義:使用共享對象有效的支持大量細粒度的對象

  • Flyweight(抽象享元角色)—— 定義對象的內部狀態和外部狀態及其對應的方法。
  • ConcreteFlyweight(具體享元角色)—— 實現抽象享元角色的方法,在具體的角色中,實現具體方法時需要注意將內部狀態與外部狀態區分開,不應出現二者同時被修改的方法。
  • unshareConcreteFlyweight(不可共享的享元角色)—— 該角色是不能使用共享技術的對象,一般在討論線程安全時使用。
  • FlyweightFactory(享元工廠)—— 負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶;如果不存在的話,則創建一個新的享元對象。

內部狀態,就是各個對象不會隨着環境的改變而改變的可共享部分;

外部狀態,指對象隨環境改變而改變的不可以共享的部分。內部狀態和外部狀態彼此互不影響,改變其中一個並不會改變另一個的行爲。

下面用C++ 代碼實現大話設計模式本章代碼:

#include <iostream>
#include<string>
#include<map>
using namespace std;

//用戶類
class User
{
private:
	string m_name;
public:
	User(string name)
	{
		m_name = name;
	}
	std::string GetName()
	{
		return m_name;
	}
};

//Flyweight類,此處爲抽象網站類
class WebSite
{
public:
	virtual ~WebSite() = default;
	virtual void Use(User user) = 0;
};

//ConcreteFlyweight類,此處爲具體網站類
class ConcreteWebSite :public WebSite
{
private:
	string m_name;
public:
	ConcreteWebSite(std::string name)
	{
		m_name = name;
	}
	void Use(User user)override
	{
		cout << "網站分類:" << m_name << "  用戶:" + user.GetName() << endl;
	}
};

//FlyweightFactory類,此處爲網站工程類
class WebSiteFactory
{
private:
	std::map<std::string, WebSite*> flyweights;
public:
	~WebSiteFactory()
	{	
		for (auto it = flyweights.begin(); it != flyweights.end(); ++it)
			delete it->second;
	}
	WebSite* GetWebSiteCategory(string key)
	{
		for (auto it = flyweights.begin(); it != flyweights.end(); ++it)
		{
			if (it->first == key)
				return it->second;
		}

		WebSite * website = new ConcreteWebSite(key);
		flyweights.insert(pair<std::string, WebSite*>(key, website));
		return website;
	}
	int GetWebSiteCount()
	{
		return flyweights.size();
	}
};

int main()
{
	WebSiteFactory f;

	WebSite* fx = f.GetWebSiteCategory("產品展示");
	fx->Use(User("小菜"));

	WebSite* fy = f.GetWebSiteCategory("產品展示");
	fy->Use(User("大鳥"));

	WebSite* fz = f.GetWebSiteCategory("產品展示");
	fz->Use(User("嬌嬌"));

	WebSite* fl = f.GetWebSiteCategory("博客");
	fl->Use(User("老頑童"));

	WebSite* fm = f.GetWebSiteCategory("博客");
	fm->Use(User("桃谷六仙"));

	WebSite* fn = f.GetWebSiteCategory("博客");
	fn->Use(User("南海鱷神"));

	cout << "得到網站分類總數:" << f.GetWebSiteCount() << endl;

	system("pause");
	return 0;
}


優點


  • 享元模式可以運用共享技術有效地支持大量細粒度的對象,大大減少對象的創建,降低系統的內存,使效率提高。

缺點


享元模式使得系統更加複雜。爲了使對象可以共享,需要將一些狀態外部化,這使得程序的邏輯複雜化。
享元模式將享元對象的狀態外部化,而讀取外部狀態使得運行時間稍微變長。


應用場景


  • 系統中存在大量相同或相似的對象,這些對象耗費大量的內存資源。
  • 大部分的對象可以按照內部狀態進行分組,且可將不同部分外部化,這樣每一個組只需保存一個內部狀態。
  • 由於享元模式需要額外維護一個保存享元的數據結構,所以應當在有足夠多的享元實例時才值得使用享元模式。

 

發佈了209 篇原創文章 · 獲贊 73 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章