|
面向?qū)ο蟮拇鷥r(jià)
面向?qū)ο蠛芎玫亟鉀Q了系統(tǒng)抽象性的問題,同時(shí)在大多數(shù)情況下,也不會(huì)損及系統(tǒng)的性能。但是,在某些特殊的應(yīng)用中,由于對(duì)象的數(shù)量太大,采用面向?qū)ο髸?huì)給系統(tǒng)帶來(lái)難以承受的內(nèi)存開銷。比如圖形應(yīng)用中的圖元等對(duì)象、字處理應(yīng)用中的字符對(duì)象等。
動(dòng)機(jī)(Motivation)
采用純粹對(duì)象方案的問題在于大量細(xì)粒度的對(duì)象會(huì)很快充斥在系統(tǒng)中,從而帶來(lái)很高的運(yùn)行時(shí)代價(jià)——主要指內(nèi)存需求方面的代價(jià)。如何在避免大量細(xì)粒度對(duì)象問題的同時(shí),讓外部客戶程序仍然能夠透明地使用面向?qū)ο蟮姆绞絹?lái)進(jìn)行操作?
意圖(Intent)
運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
——《設(shè)計(jì)模式》GoF
例說(shuō)Flyweight應(yīng)用
如果是對(duì)字符char使用享元模式,本來(lái)每個(gè)字符只占用2字節(jié),而享元模式要使用指針,至少每個(gè)字符需要4字節(jié),這樣就適得其反了,反而消耗了更多的內(nèi)存資源。
但是字體就需要用享元模式了,因?yàn)樗拇笮”茸址蟮枚啵谖覀冞@個(gè)例子中有12bytes,如果是它倍乘的話數(shù)量級(jí)就很大了,很消耗內(nèi)存。
其實(shí)更精確地說(shuō),對(duì)于C#,每一個(gè)類還需要有一個(gè)虛表指針和做垃圾回收控制的空間,一共占8bytes。因?yàn)镃#中每一個(gè)類都是繼承自object類,所以每個(gè)類都帶有虛函數(shù)和類型信息。所以Font類應(yīng)該是20bytes的倍乘效應(yīng)。在Charactor類中,char字符占2bytes;Font類型有個(gè)指針,占4bytes;還有Font里的20bytes;還有8bytes的虛表指針和垃圾回收;因?yàn)?2位機(jī)器上有一個(gè)填充的效應(yīng),char字符還需要額外占用2bytes,需要補(bǔ)齊;因此Charactor類共占36bytes。在客戶代碼中,有100000個(gè)Charactor類,那么大約在會(huì)帶來(lái)3.6M的數(shù)據(jù)。如果是服務(wù)器程序,那么3M數(shù)據(jù)可以接受。但如果字符數(shù)量級(jí)再增加,那么開銷是不言而喻的。
改善結(jié)構(gòu):
Charactor類里的CFont屬性
這里當(dāng)我們使用Charactor的時(shí)候,我們?cè)O(shè)置它字體時(shí),如果在它靜態(tài)的Hashtable里面已經(jīng)有的話,我們就把指針直接指向它,就不要再去新建一個(gè)字體對(duì)象了
客戶代碼中第61行和63行,f1和f2占用兩塊不同的內(nèi)存,但是到了68行和73行,我們實(shí)際上在內(nèi)部透明的把它們轉(zhuǎn)化為讓它們只用f1一塊內(nèi)存,f2的內(nèi)存就不會(huì)再讓它持有。
要注意的是,在.NET里面使用字符串的時(shí)候,它實(shí)際上已經(jīng)運(yùn)用了享元模式,比如我們字符串里出了20個(gè)“Hello World”,實(shí)際上在系統(tǒng)里面只存了1個(gè)“Hello World”,其它的都是用指針指向它。這個(gè)前提當(dāng)然是字符串的代價(jià)比指針大。
結(jié)構(gòu)(Structure)
這種結(jié)構(gòu)其實(shí)可以僅作為參考,它并不是一個(gè)作為絕對(duì)標(biāo)準(zhǔn)化的結(jié)構(gòu)。基本思路實(shí)現(xiàn)是這樣,但是至于是否有必要放到一個(gè)靜態(tài)工廠來(lái)做,還值得商榷。像我們上面的例子就直接把它放在一個(gè)屬性里面去做。
Flyweight模式的幾個(gè)要點(diǎn)
面向?qū)ο蠛芎玫亟鉀Q了抽象性的問題,但是作為一個(gè)運(yùn)行在機(jī)器中的程序?qū)嶓w,我們需要考慮對(duì)象的代價(jià)問題。Flyweight設(shè)計(jì)模式主要解決面向?qū)ο蟮拇鷥r(jià)問題,一般不觸及面向?qū)ο蟮某橄笮詥栴}。Flyweight采用對(duì)象共享的做法來(lái)降低系統(tǒng)中對(duì)象的個(gè)數(shù),從而降低細(xì)粒度對(duì)象給系統(tǒng)帶來(lái)的內(nèi)存壓力。在具體實(shí)現(xiàn)方面,要注意對(duì)象狀態(tài)的處理。
對(duì)象的數(shù)量太大從而導(dǎo)致對(duì)象內(nèi)存開銷加大——什么樣的數(shù)量才算大?這需要我們仔細(xì)的根據(jù)具體應(yīng)用情況進(jìn)行評(píng)估,而不能憑空臆斷。
.NET架構(gòu)中的Flyweight應(yīng)用
.NET在C#中有一個(gè)Code Behind機(jī)制,它表面有一個(gè)ASPx文件,背后又有一個(gè)cs文件,它的編譯過程實(shí)際上會(huì)把ASPx文件解析成C#文件,然后編譯成dll,在這個(gè)過程中,我們?cè)?a href=/itjie/ASPjishu/ target=_blank class=infotextkey>ASPx中寫的任何html代碼都會(huì)轉(zhuǎn)化為literal control,literal control是一個(gè)一般的文本控件,它就表示html標(biāo)記。當(dāng)這些標(biāo)記有一樣的時(shí)候,構(gòu)建控件樹的時(shí)候就會(huì)用到Flyweight模式.
它的應(yīng)用并不是那么平凡,只有在效率空間確實(shí)不高的時(shí)候我們才用它。
it知識(shí)庫(kù):C#面向?qū)ο笤O(shè)計(jì)模式縱橫談:Flyweight 享元模式,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。