概述:
在項(xiàng)目開發(fā)中我們有時(shí)候需要控制一些細(xì)密度的集合類,通常的做法是系統(tǒng)實(shí)例化每一個(gè)類進(jìn)行指定的業(yè)務(wù)操作,這時(shí)系統(tǒng)需要消耗很多的內(nèi)存,如果類過(guò)多的話將會(huì)把內(nèi)存給撐爆掉。有種做法就是不用面向?qū)ο螅呛菍?duì)!的確可以但這個(gè)和你整個(gè)系統(tǒng)采用面向?qū)ο蟪绦蛟O(shè)計(jì)又有些格格不入。那么我們?nèi)绾伪苊獯罅考?xì)粒度的對(duì)象,同時(shí)又不影響客戶程序使用面向?qū)ο蟮牟僮髂兀课覀兿葋?lái)看個(gè)簡(jiǎn)單的超市進(jìn)銷存的例子(這里我精簡(jiǎn)了一些,列出了部分對(duì)象屬性。)
需求:將商品做出倉(cāng)入倉(cāng)管理
需求很簡(jiǎn)單,打個(gè)比方,最近超市蛋黃派(汗!又是蛋黃派。沒(méi)辦法本人天天早餐就是一個(gè)蛋黃派)賣的比較火超市倉(cāng)庫(kù)出貨進(jìn)貨比較頻繁。正常的設(shè)計(jì)是有一個(gè)蛋黃派我就實(shí)例化一個(gè),然后存入倉(cāng)庫(kù)。這里就出現(xiàn)了很大的問(wèn)題,如果有 1000 袋要入倉(cāng) 1000 袋要出倉(cāng)那我們要實(shí)例化 2000 個(gè)這樣的類,這樣對(duì)內(nèi)存消耗和處理性能來(lái)說(shuō)都是有很大負(fù)擔(dān)的。這時(shí)我們需要一種方式來(lái)解決這個(gè)問(wèn)題,享元模式就是專門處理這樣的情況的。享元模式用于處理大量細(xì)粒度的對(duì)象。那么我們就用它來(lái)處理上面的問(wèn)題
看下圖:
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 248.25pt; HEIGHT: 317.25pt" type="#_x0000_t75"><imagedata o:title="flayWeigth-1" src="file:///C:%5CDOCUME~1%5CFANWEI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.jpg"></imagedata></shape>
解釋:
1. 定義一個(gè) commodity 商品,對(duì)于倉(cāng)庫(kù)來(lái)講 他們統(tǒng)計(jì)商品只需要知道每種商品的條形碼和庫(kù)存量,至于其他的屬性沒(méi)有必要一一了解。
2. 定義一個(gè)蛋黃派類實(shí)現(xiàn) commodity 抽象類中的 in 、 out 方法
3. 定義一個(gè)商品供應(yīng)商 CakeAccommodate 他組要負(fù)責(zé)向超市供應(yīng)商品,當(dāng)供應(yīng)商沒(méi)有經(jīng)營(yíng)一個(gè)商品時(shí)他會(huì)立刻建立這個(gè)商品的采購(gòu)渠道保證商品的正常供給
這里也許大家會(huì)問(wèn)怎么說(shuō)了半天倉(cāng)庫(kù),倉(cāng)庫(kù)這個(gè)類都沒(méi)有,這里我做了簡(jiǎn)化,如果你愿意可以再建一個(gè)倉(cāng)庫(kù)類和超市類出來(lái),我這里將 commodity 設(shè)計(jì)成了一個(gè)存放商品的空間,可能名字取的不好吧!如果你想完善他可以自行設(shè)計(jì)一個(gè),這里我只是圖了個(gè)方便省事,首先在在這里聲明這不是一個(gè)很好的對(duì)象設(shè)計(jì) . 只是為了說(shuō)明享元模式。 Commodity 這里你可以理解為存放某類商品的存儲(chǔ)空間
代碼:
private static void SimplenFlyWeigth()
{
CakeAccommodate acc = new CakeAccommodate ();
Commodity gm = acc.GetCakes( " 光明 " );
gm.In(20);
Commodity wg = acc.GetCakes( " 衛(wèi)崗 " );
wg.In(25);
Commodity wm = acc.GetCakes( " 無(wú)名 " );
wm.In(10);
gm.Out(30);
gm.In(10);
gm.Out(30);
wg.Out(5);
wm.Out(1);
//Console.ReadLine();
}
效果 :
<shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 276pt" type="#_x0000_t75"><imagedata o:title="flayWeigth-3" src="file:///C:%5CDOCUME~1%5CFANWEI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image002.jpg"></imagedata></shape>
但真正的倉(cāng)儲(chǔ)沒(méi)那么簡(jiǎn)單,往往每批貨物都是規(guī)整放到指定位置的,那么這樣就需要我們依據(jù)不同的位置存放商品,這里我們引入復(fù)合享元模式的機(jī)制。通過(guò)傳入?yún)?shù)動(dòng)態(tài)控制細(xì)粒度對(duì)象的業(yè)務(wù)邏輯
看下圖:
<shape id="_x0000_i1027" style="WIDTH: 374.25pt; HEIGHT: 335.25pt" type="#_x0000_t75"><imagedata o:title="flayWeigth-2" src="file:///C:%5CDOCUME~1%5CFANWEI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image004.jpg"></imagedata></shape>
1. PointCommodity :指定的某種類存儲(chǔ)位置
2. ShelfPoint :貨架
3. PointCake :存放在指定貨架上的蛋黃派
4. CakeAccommodate :蛋黃派供應(yīng)商
運(yùn)行效果:
<shape id="_x0000_i1028" style="WIDTH: 415.5pt; HEIGHT: 277.5pt" type="#_x0000_t75"><imagedata o:title="flayWeigth-4" src="file:///C:%5CDOCUME~1%5CFANWEI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.jpg"></imagedata></shape>
OOD 設(shè)計(jì)合理性:
1. 是否符合開不原則:
如果我們需要再加一種商品進(jìn)來(lái)的話我們只需要新建一個(gè)類繼承 Commodity 抽象 類就可以了,不用修改其他類
符合
2. 是否符合里氏代換:
符合
3. 是否符合抽象原則
符合
4. 是否符合迪米特法則
符合
享元模式總結(jié)
意圖:
運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象
結(jié)構(gòu)圖:
<shape id="_x0000_i1029" style="WIDTH: 321.75pt; HEIGHT: 201pt" type="#_x0000_t75"><imagedata o:title="flayWeigth-5" src="file:///C:%5CDOCUME~1%5CFANWEI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image007.jpg"></imagedata></shape>
享元模式所涉及的角色有抽象享元角色、具體享元角色、復(fù)合享元角色、享員工廠角色,以及客戶端角色等。
抽象享元角色: 此角色是所有的具體享元類的超類,為這些類規(guī)定出需要實(shí)現(xiàn)的公共接口。那些需要外蘊(yùn)狀態(tài) (External State) 的操作可以通過(guò)方法的參數(shù)傳入。抽象享元的接口使得享元變得可能,但是并不強(qiáng)制子類實(shí)行共享,因此并非所有的享元對(duì)象都是可以共享的。
具體享元 (ConcreteFlyweight) 角色: 實(shí)現(xiàn)抽象享元角色所規(guī)定的接口。如果有內(nèi)蘊(yùn)狀態(tài)的話,必須負(fù)責(zé)為內(nèi)蘊(yùn)狀態(tài)提供存儲(chǔ)空間。享元對(duì)象的內(nèi)蘊(yùn)狀態(tài)必須與對(duì)象所處的周圍環(huán)境無(wú)關(guān),從而使得享元對(duì)象可以在系統(tǒng)內(nèi)共享。有時(shí)候具體享元角色又叫做單純具體享元角色,因?yàn)閺?fù)合享元角色是由單純具體享元角色通過(guò)復(fù)合而成的。
復(fù)合享元 (UnsharableFlyweight) 角色: 復(fù)合享元角色所代表的對(duì)象是不可以共享的,但是一個(gè)復(fù)合享元對(duì)象可以分解成為多個(gè)本身是單純享元對(duì)象的組合。復(fù)合享元角色又稱做不可共享的享元對(duì)象。
享元工廠 (FlyweightFactoiy) 角色: 本角色負(fù)責(zé)創(chuàng)建和管理享元角色。本角色必須保證享元對(duì)象可以被系統(tǒng)適當(dāng)?shù)毓蚕怼.?dāng)一個(gè)客戶端對(duì)象請(qǐng)求一個(gè)享元對(duì)象的時(shí)候,享元工廠角色需要檢查系統(tǒng)中是否已經(jīng)有一個(gè)符合要求的享元對(duì)象,如果已經(jīng)有了,享元工廠角色就應(yīng)當(dāng)提供這個(gè)已有的享元對(duì)象;如果系統(tǒng)中沒(méi)有一個(gè)適當(dāng)?shù)南碓獙?duì)象的話,享元工廠角色就應(yīng)當(dāng)創(chuàng)建一個(gè)新的合適的享元對(duì)象。
客戶端 (Client) 角色: 本角色還需要自行存儲(chǔ)所有享元對(duì)象的外蘊(yùn)狀態(tài)
使用背景:
1. 一個(gè)系統(tǒng)有大量的對(duì)象。
2. 這些對(duì)象耗費(fèi)大量的內(nèi)存。
3. 這些對(duì)象的狀態(tài)中的大部分都可以外部化。
4. 這些對(duì)象可以按照內(nèi)蘊(yùn)狀態(tài)分成很多的組,當(dāng)把外蘊(yùn)對(duì)象從對(duì)象中剔除時(shí),每一個(gè)組都可以僅用一個(gè)對(duì)象代替。
5. 軟件系統(tǒng)不依賴于這些對(duì)象的身份,換言之,這些對(duì)象可以是不可分辨的。
模式優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1. 大大節(jié)約了存儲(chǔ)空間
備注:
Flyweight 在拳擊比賽中指最輕量級(jí),即 " 蠅量級(jí) " ,有些作者翻譯為 " 羽量級(jí) " 。這里使用 " 享元模式 " 更能反映模式的用意。
享元模式以共享的方式高效地支持大量的細(xì)粒度對(duì)象。享元對(duì)象能做到共享的關(guān)鍵是區(qū)分內(nèi)蘊(yùn)狀態(tài)( Internal State )和外蘊(yùn)狀態(tài)( External State )。內(nèi)蘊(yùn)狀態(tài)是存儲(chǔ)在享元對(duì)象內(nèi)部并且不會(huì)隨環(huán)境改變而改變。因此內(nèi)蘊(yùn)狀態(tài)并可以共享。
外蘊(yùn)狀態(tài)是隨環(huán)境改變而改變的、不可以共享的狀態(tài)。享元對(duì)象的外蘊(yùn)狀態(tài)必須由客戶端保存,并在享元對(duì)象被創(chuàng)建之后,在需要使用的時(shí)候再傳入到享元對(duì)象內(nèi)部。外蘊(yùn)狀態(tài)與內(nèi)蘊(yùn)狀態(tài)是相互獨(dú)立的。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
