講解C#設(shè)計(jì)模式編程中享元模式的運(yùn)用
一、概述
在軟件開(kāi)發(fā)中,我們有時(shí)需要?jiǎng)?chuàng)建大量細(xì)粒度的對(duì)象,比如文檔處理系統(tǒng)就可能需要?jiǎng)?chuàng)建成千上萬(wàn)的字符對(duì)象。但如果對(duì)每個(gè)字符對(duì)象都分配內(nèi)存,那么在系統(tǒng)運(yùn)行時(shí)就會(huì)耗費(fèi)大量的內(nèi)存。如何在保留面向?qū)ο蟛僮鞣绞絻?yōu)點(diǎn)的同時(shí)避免創(chuàng)建大量的對(duì)象呢?這就到了享元模式發(fā)揮作用的時(shí)候了。
二、享元模式
享元模式運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。例如可以對(duì)文檔處理系統(tǒng)創(chuàng)建共享池,在共享池中建立字母和代碼的對(duì)應(yīng)關(guān)系,這樣就可以用共享池中的26個(gè)對(duì)象解決需要?jiǎng)?chuàng)建大量對(duì)象的問(wèn)題。其結(jié)構(gòu)圖如下:
Flyweight定義了享元接口,外部對(duì)象通過(guò)這個(gè)接口來(lái)訪問(wèn)具體的享元對(duì)象。
ConcreteFlyweight實(shí)現(xiàn)Flyweight接口,定義了具體的享元對(duì)象,并保存享元對(duì)象的內(nèi)部狀態(tài)。該享元對(duì)象是可共享的。
UnsharedConcreteFlyweight實(shí)現(xiàn)Flyweight接口,定義了不用于共享的享元對(duì)象。
FlyweightFactory創(chuàng)建并管理享元對(duì)象。
Client保存對(duì)享元接口的引用,通過(guò)該引用有效的使用具體的享元對(duì)象。
三、示例
下面以一個(gè)實(shí)際的應(yīng)用來(lái)實(shí)現(xiàn)下享元模式。這個(gè)例子是:一個(gè)文本編輯器中會(huì)出現(xiàn)很多字面,使用享元模式去實(shí)現(xiàn)這個(gè)文本編輯器的話,會(huì)把每個(gè)字面做成一個(gè)享元對(duì)象。享元對(duì)象的內(nèi)部狀態(tài)就是這個(gè)字面,而字母在文本中的位置和字體風(fēng)格等其他信息就是它的外部狀態(tài)。下面就以這個(gè)例子來(lái)實(shí)現(xiàn)下享元模式,具體實(shí)現(xiàn)代碼如下:
/// <summary> /// 客戶(hù)端調(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)建的對(duì)象A Flyweight fa = factory.GetFlyweight("A"); if (fa != null) { // 把外部狀態(tài)作為享元對(duì)象的方法調(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"); // 這時(shí)候就需要?jiǎng)?chuàng)建一個(gè)對(duì)象并放入駐留池中 ConcreteFlyweight d = new ConcreteFlyweight("D"); factory.flyweights.Add("D", d); } Console.Read(); } } /// <summary> /// 享元工廠,負(fù)責(zé)創(chuàng)建和管理享元對(duì)象 /// </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) { // 更好的實(shí)現(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> /// 抽象享元類(lèi),提供具體享元類(lèi)具有的方法 /// </summary> public abstract class Flyweight { public abstract void Operation(int extrinsicstate); } // 具體的享元對(duì)象,這樣我們不把每個(gè)字母設(shè)計(jì)成一個(gè)單獨(dú)的類(lèi)了,而是作為把共享的字母作為享元對(duì)象的內(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> /// 享元類(lèi)的實(shí)例方法 /// </summary> /// <param name="extrinsicstate">外部狀態(tài)</param> public override void Operation(int extrinsicstate) { Console.WriteLine("具體實(shí)現(xiàn)類(lèi): intrinsicstate {0}, extrinsicstate {1}", intrinsicstate, extrinsicstate); } }
在享元模式的實(shí)現(xiàn)中,我們沒(méi)有像之前一樣,把一個(gè)細(xì)粒度的類(lèi)實(shí)例設(shè)計(jì)成一個(gè)單獨(dú)的類(lèi),而是把它作為共享對(duì)象的內(nèi)部狀態(tài)放在共享類(lèi)的內(nèi)部定義。
四、享元模式的優(yōu)缺點(diǎn)
分析完享元模式的實(shí)現(xiàn)之后,讓我們繼續(xù)分析下享元模式的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
降低了系統(tǒng)中對(duì)象的數(shù)量,從而降低了系統(tǒng)中細(xì)粒度對(duì)象給內(nèi)存帶來(lái)的壓力。
缺點(diǎn):
1.為了使對(duì)象可以共享,需要將一些狀態(tài)外部化,這使得程序的邏輯更復(fù)雜,使系統(tǒng)復(fù)雜化。
2.享元模式將享元對(duì)象的狀態(tài)外部化,而讀取外部狀態(tài)使得運(yùn)行時(shí)間稍微變長(zhǎng)。
五、使用場(chǎng)景
在下面所有條件都滿(mǎn)足時(shí),可以考慮使用享元模式:
- 一個(gè)系統(tǒng)中有大量的對(duì)象;
- 這些對(duì)象耗費(fèi)大量的內(nèi)存;
- 這些對(duì)象中的狀態(tài)大部分都可以被外部化;
- 這些對(duì)象可以按照內(nèi)部狀態(tài)分成很多的組,當(dāng)把外部對(duì)象從對(duì)象中剔除時(shí),每一個(gè)組都可以?xún)H用一個(gè)對(duì)象代替;
- 軟件系統(tǒng)不依賴(lài)這些對(duì)象的身份。
滿(mǎn)足上面的條件的系統(tǒng)可以使用享元模式。但是使用享元模式需要額外維護(hù)一個(gè)記錄子系統(tǒng)已有的所有享元的表,而這也需要耗費(fèi)資源,所以,應(yīng)當(dāng)在有足夠多的享元實(shí)例可共享時(shí)才值得使用享元模式。
上一篇:解析C#設(shè)計(jì)模式編程中備忘錄模式的運(yùn)用
欄 目:C#教程
本文標(biāo)題:講解C#設(shè)計(jì)模式編程中享元模式的運(yùn)用
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6673.html
您可能感興趣的文章
- 01-10C#編程實(shí)現(xiàn)自定義熱鍵的方法
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10深入淺出23種設(shè)計(jì)模式
- 01-10C#日歷樣式的下拉式計(jì)算器實(shí)例講解
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類(lèi)型和變量二
- 01-10C#編程自學(xué)之開(kāi)篇介紹
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類(lèi)型和變量三
- 01-10C#編程自學(xué)之運(yùn)算符和表達(dá)式
- 01-10C#導(dǎo)出網(wǎng)站功能實(shí)例代碼講解
- 01-10C#編程自學(xué)之類(lèi)和對(duì)象


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過(guò)重寫(xiě)Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載