在軟件開發(fā)過程,如果我們需要重復(fù)使用某個對象的時候,如果我們重復(fù)地使用new創(chuàng)建這個對象的話,這樣我們在內(nèi)存就需要多次地去申請內(nèi)存空間了,這樣可能會出現(xiàn)內(nèi)存使用越來越多的情況,這樣的問題是非常嚴(yán)重,然而享元模式可以解決這個問題,下面具體看看享元模式是如何去解決這個問題的。
在前面說了,享元模式可以解決上面的問題了,在介紹享元模式之前,讓我們先要分析下如果去解決上面那個問題,上面的問題就是重復(fù)創(chuàng)建了同一個對象,如果讓我們?nèi)ソ鉀Q這個問題肯定會這樣想:“既然都是同一個對象,能不能只創(chuàng)建一個對象,然后下次需要創(chuàng)建這個對象的時候,讓它直接用已經(jīng)創(chuàng)建好了的對象就好了”,也就是說——讓一個對象共享。不錯,這個也是享元模式的實現(xiàn)精髓所在。
介紹完享元模式的精髓之后,讓我們具體看看享元模式的正式定義:
享元模式——運用共享技術(shù)有效地支持大量細粒度的對象。享元模式可以避免大量相似類的開銷,在軟件開發(fā)中如果需要生成大量細粒度的類實例來表示數(shù)據(jù),如果這些實例除了幾個參數(shù)外基本上都是相同的,這時候就可以使用享元模式來大幅度減少需要實例化類的數(shù)量。如果能把這些參數(shù)(指的這些類實例不同的參數(shù))移動類實例外面,在方法調(diào)用時將他們傳遞進來,這樣就可以通過共享大幅度地減少單個實例的數(shù)目。(這個也是享元模式的實現(xiàn)要領(lǐng)),然而我們把類實例外面的參數(shù)稱為享元對象的外部狀態(tài),把在享元對象內(nèi)部定義稱為內(nèi)部狀態(tài)。具體享元對象的內(nèi)部狀態(tài)與外部狀態(tài)的定義為:
內(nèi)部狀態(tài):在享元對象的內(nèi)部并且不會隨著環(huán)境的改變而改變的共享部分
外部狀態(tài):隨環(huán)境改變而改變的,不可以共享的狀態(tài)。
分析完享元模式的實現(xiàn)思路之后,相信大家實現(xiàn)享元模式肯定沒什么問題了,下面以一個世紀(jì)的應(yīng)用來實現(xiàn)下享元模式。這個例子是:一個文本編輯器中會出現(xiàn)很多字面,使用享元模式去實現(xiàn)這個文本編輯器的話,會把每個字面做成一個享元對象。享元對象的內(nèi)部狀態(tài)就是這個字面,而字母在文本中的位置和字體風(fēng)格等其他信息就是它的外部狀態(tài)。下面就以這個例子來實現(xiàn)下享元模式,具體實現(xiàn)代碼如下:
/// <summary> /// 客戶端調(diào)用 /// </summary> class Client { static void Main(string[] args) { // 定義外部狀態(tài),例如字母的位置等信息 int externalstate = 10; // 初始化享元工廠 FlyweightFactory factory = new FlyweightFactory(); // 判斷是否已經(jīng)創(chuàng)建了字母A,如果已經(jīng)創(chuàng)建就直接使用創(chuàng)建的對象A Flyweight fa = factory.GetFlyweight("A"); if (fa != null) { // 把外部狀態(tài)作為享元對象的方法調(diào)用參數(shù) fa.Operation(--externalstate); } // 判斷是否已經(jīng)創(chuàng)建了字母B Flyweight fb = factory.GetFlyweight("B"); if (fb != null) { fb.Operation(--externalstate); } // 判斷是否已經(jīng)創(chuàng)建了字母C Flyweight fc = factory.GetFlyweight("C"); if (fc != null) { fc.Operation(--externalstate); } // 判斷是否已經(jīng)創(chuàng)建了字母D Flyweight fd= factory.GetFlyweight("D"); if (fd != null) { fd.Operation(--externalstate); } else { Console.WriteLine("駐留池中不存在字符串D"); // 這時候就需要創(chuàng)建一個對象并放入駐留池中 ConcreteFlyweight d = new ConcreteFlyweight("D"); factory.flyweights.Add("D", d); } Console.Read(); } } /// <summary> /// 享元工廠,負責(zé)創(chuàng)建和管理享元對象 /// </summary> public class FlyweightFactory { // 最好使用泛型Dictionary<string,Flyweighy> //public Dictionary<string, Flyweight> flyweights = new Dictionary<string, Flyweight>(); public Hashtable flyweights = new Hashtable(); public FlyweightFactory() { flyweights.Add("A", new ConcreteFlyweight("A")); flyweights.Add("B", new ConcreteFlyweight("B")); flyweights.Add("C", new ConcreteFlyweight("C")); } public Flyweight GetFlyweight(string key) { // 更好的實現(xiàn)如下 //Flyweight flyweight = flyweights[key] as Flyweight; //if (flyweight == null) //{ // Console.WriteLine("駐留池中不存在字符串" + key); // flyweight = new ConcreteFlyweight(key); //} //return flyweight; return flyweights[key] as Flyweight; } } /// <summary> /// 抽象享元類,提供具體享元類具有的方法 /// </summary> public abstract class Flyweight { public abstract void Operation(int extrinsicstate); } // 具體的享元對象,這樣我們不把每個字母設(shè)計成一個單獨的類了,而是作為把共享的字母作為享元對象的內(nèi)部狀態(tài) public class ConcreteFlyweight : Flyweight { // 內(nèi)部狀態(tài) private string intrinsicstate ; // 構(gòu)造函數(shù) public ConcreteFlyweight(string innerState) { this.intrinsicstate = innerState; } /// <summary> /// 享元類的實例方法 /// </summary> /// <param name="extrinsicstate">外部狀態(tài)</param> public override void Operation(int extrinsicstate) { Console.WriteLine("具體實現(xiàn)類: intrinsicstate {0}, extrinsicstate {1}", intrinsicstate, extrinsicstate); } }
在享元模式的實現(xiàn)中,我們沒有像之前一樣,把一個細粒度的類實例設(shè)計成一個單獨的類,而是把它作為共享對象的內(nèi)部狀態(tài)放在共享類的內(nèi)部定義,具體的解釋注釋中都有了,大家可以參考注釋去進一步理解享元模式。
看完享元模式的實現(xiàn)之后,為了幫助大家理清楚享元模式中各類之間的關(guān)系,下面給出上面實現(xiàn)代碼中的類圖,如下所示:
(摘自http://www.cnblogs.com/zhenyulu/articles/55793.html)
在上圖中,涉及的角色如下幾種角色:
抽象享元角色(Flyweight):此角色是所有的具體享元類的基類,為這些類規(guī)定出需要實現(xiàn)的公共接口。那些需要外部狀態(tài)的操作可以通過調(diào)用方法以參數(shù)形式傳入。
具體享元角色(ConcreteFlyweight):實現(xiàn)抽象享元角色所規(guī)定的接口。如果有內(nèi)部狀態(tài)的話,可以在類內(nèi)部定義。
享元工廠角色(FlyweightFactory):本角色復(fù)雜創(chuàng)建和管理享元角色。本角色必須保證享元對象可以被系統(tǒng)適當(dāng)?shù)毓蚕?,?dāng)一個客戶端對象調(diào)用一個享元對象的時候,享元工廠角色檢查系統(tǒng)中是否已經(jīng)有一個符合要求的享元對象,如果已經(jīng)存在,享元工廠角色就提供已存在的享元對象,如果系統(tǒng)中沒有一個符合的享元對象的話,享元工廠角色就應(yīng)當(dāng)創(chuàng)建一個合適的享元對象。
客戶端角色(Client):本角色需要存儲所有享元對象的外部狀態(tài)。
注:上面的實現(xiàn)只是單純的享元模式,同時還有復(fù)合的享元模式,由于復(fù)合享元模式較復(fù)雜,這里就不給出實現(xiàn)了。
分析完享元模式的實現(xiàn)之后,讓我們繼續(xù)分析下享元模式的優(yōu)缺點:
優(yōu)點:
降低了系統(tǒng)中對象的數(shù)量,從而降低了系統(tǒng)中細粒度對象給內(nèi)存帶來的壓力。
缺點:
為了使對象可以共享,需要將一些狀態(tài)外部化,這使得程序的邏輯更復(fù)雜,使系統(tǒng)復(fù)雜化。
享元模式將享元對象的狀態(tài)外部化,而讀取外部狀態(tài)使得運行時間稍微變長。
在下面所有條件都滿足時,可以考慮使用享元模式:
一個系統(tǒng)中有大量的對象;
這些對象耗費大量的內(nèi)存;
這些對象中的狀態(tài)大部分都可以被外部化
這些對象可以按照內(nèi)部狀態(tài)分成很多的組,當(dāng)把外部對象從對象中剔除時,每一個組都可以僅用一個對象代替
軟件系統(tǒng)不依賴這些對象的身份,
滿足上面的條件的系統(tǒng)可以使用享元模式。但是使用享元模式需要額外維護一個記錄子系統(tǒng)已有的所有享元的表,而這也需要耗費資源,所以,應(yīng)當(dāng)在有足夠多的享元實例可共享時才值得使用享元模式。
注:在.NET類庫中,string類的實現(xiàn)就使用了享元模式,更多內(nèi)容可以參考字符串駐留池的介紹,同時也可以參考這個博文深入理解.NET中string類的設(shè)計——http://www.cnblogs.com/artech/archive/2010/11/25/internedstring.html
到這里,享元模式的介紹就結(jié)束了,享元模式主要用來解決由于大量的細粒度對象所造成的內(nèi)存開銷的問題,它在實際的開發(fā)中并不常用,可以作為底層的提升性能的一種手段。
附件:http://down.51cto.com/data/2363665另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
分享文章:C#設(shè)計模式(12)——享元模式(FlyweightPattern)-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://www.rwnh.cn/article14/dosgge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計、關(guān)鍵詞優(yōu)化、App開發(fā)、ChatGPT、手機網(wǎng)站建設(shè)、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)