大家好,我是每周在里陪你進(jìn)步的網(wǎng)管~本次我們繼續(xù)填坑,一下裝飾器模式。上文章我們說(shuō)過(guò)裝飾器代理模式的特殊應(yīng)用而且很多人說(shuō)中間件用裝飾器模式實(shí)現(xiàn)的有的人說(shuō)是用職責(zé)鏈現(xiàn)的,那么這篇文章們就來(lái)一起看看他們異同。什么是裝飾器飾器模式(Decorator Pattern)也叫作包裝器模式(Wrapper Pattern),指在不改變?cè)袑?duì)象的礎(chǔ)上,動(dòng)態(tài)地給一個(gè)象添加一些額外的職。就增加功能來(lái)說(shuō),飾器模式相比生成子更為靈活,屬于結(jié)構(gòu)設(shè)計(jì)模式。給對(duì)象添新行為最簡(jiǎn)單直觀的法就是擴(kuò)展本體對(duì)象通過(guò)繼承的方式達(dá)到的。但是使用繼承不避免地有如下兩個(gè)弊:繼承是靜態(tài)的,在譯期間就已經(jīng)確定,法在運(yùn)行時(shí)改變對(duì)象行為。子類只能有一父類,當(dāng)需要添加的功能太多時(shí),容易導(dǎo)類的數(shù)量劇增。而使裝飾器模式,我們通將現(xiàn)有對(duì)象放置在實(shí)了相同一套接口的包器對(duì)象中來(lái)動(dòng)態(tài)地向有對(duì)象添加新行為。包裝器中進(jìn)行我們代的擴(kuò)展,有助于重用能并且不會(huì)修改現(xiàn)有象的代碼,符合“開原則”。這里被放置包裝對(duì)象的“現(xiàn)有對(duì)”通常會(huì)被叫做“組”(Component),而包裝組件的包裝器對(duì)狌狌就是我們常的“裝飾器”(Decorator),因?yàn)檠b飾器會(huì)組件實(shí)現(xiàn)相接口,故客戶端無(wú)法別兩者的差異,也就需要在增加裝飾器時(shí)客戶端調(diào)用代碼進(jìn)行改了。從上面關(guān)于裝器模式的描述中 ,會(huì)感覺(jué)他跟代理模式很。這是因?yàn)樗麄儽緛?lái)結(jié)構(gòu)上也幾乎一樣,飾器算是代理的一個(gè)殊應(yīng)用--裝飾器模式的一個(gè)特點(diǎn)是可以嵌多層裝飾器,相當(dāng)于代理再加代理。不過(guò)理強(qiáng)調(diào)的是對(duì)本體對(duì)的訪問(wèn)控制,而裝飾是用來(lái)對(duì)本地進(jìn)行增,兩者在使用目的上一樣。上面裝飾器模的用處特點(diǎn)用文字描了這么多,下面我們 UML 類圖展示一下它的結(jié)構(gòu),讓我們寫代碼前對(duì)模式中的個(gè)角色有個(gè)更清晰的識(shí)。裝飾器的結(jié)構(gòu)用 UML 類圖表示裝飾器模式的結(jié)幾山如下:圖中可以看到裝飾器式中主要有如下幾個(gè)色:客戶端:會(huì)用多裝飾器來(lái)封裝組件,后調(diào)用裝飾好的包裝的方法,啟動(dòng)執(zhí)行。件接口:Component 聲明裝飾器對(duì)象和被裝飾的組件對(duì)要實(shí)現(xiàn)的公用接口。件實(shí)現(xiàn):具體的組件現(xiàn)類它的 Operation 方法中定義了組件的基葛山行為,飾類可以增強(qiáng)這些行?;A(chǔ)裝飾類:擁有個(gè)指向被封裝對(duì)象的員變量。在自己的 Operation 方法中調(diào)用被裝飾對(duì)象 Operation 方法具體裝飾類:重寫父類的 Operation 方法實(shí)現(xiàn)增強(qiáng)邏輯。類弄明里已經(jīng)出了要實(shí)現(xiàn)的主要邏,第四步的基礎(chǔ)裝飾并不需要一定存在,全可以由具體裝飾類持有對(duì)被裝飾對(duì)象的用,并實(shí)現(xiàn)增強(qiáng)邏輯這樣一來(lái)整體的結(jié)構(gòu)更簡(jiǎn)單一些。注意:中的方法名在代碼實(shí)里可自己定義,不需完全跟圖里給出的方名一樣。我們可以跟節(jié)代理模式的 UML 類圖做個(gè)對(duì)比,兩者在結(jié)構(gòu)上非常相似,其是省略了 BaseDecorator 這一層后,在結(jié)構(gòu)上本上是一摸一樣,這我們一直再?gòu)?qiáng)調(diào)的--"裝飾器是代理模式的特殊應(yīng)無(wú)淫" 的一個(gè)論據(jù)。下面我們看一下現(xiàn)裝飾器模式的代碼版,本文中提供了 Go 語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單裝飾器模式的代碼模。裝飾器模式代碼實(shí)清楚了裝飾器模式結(jié)的組成后,再來(lái)寫代就會(huì)清晰很多,接下我們演示一下用裝飾模式實(shí)現(xiàn)增強(qiáng)游戲主的一個(gè)例子。首先我定義一個(gè)游戲主機(jī)的品接口,它就是上面圖中組件和裝飾器的共接口。//?PS5?產(chǎn)品接口type?PS5?interface?{?StartGPUEngine()?GetPrice()?int64}然后我們提供一個(gè)基的產(chǎn)品實(shí)現(xiàn)類作為裝器模式中的組件。//?CD?版?PS5主機(jī)"本文使用的完整可運(yùn)行源申鑒去公眾號(hào)「管叨bi叨」發(fā)送【設(shè)計(jì)模式】即可領(lǐng)取"type?PS5WithCD?struct{}func?(p?PS5WithCD)?StartGPUEngine()?{?fmt.Println("start?engine")}func?(p?PS5WithCD)?GetPrice()?int64?{?return?5000}這里給出的是一個(gè) CD 版的游戲主機(jī),平時(shí)游戲的同學(xué)都會(huì)知道一般還會(huì)有數(shù)字版的機(jī),價(jià)格會(huì)便宜點(diǎn),種情況我們可以提供個(gè)數(shù)字版游戲主機(jī)的現(xiàn)作為組件實(shí)現(xiàn)類。//?PS5?數(shù)字版主機(jī)type?PS5WithDigital?struct{}func?(p?PS5WithDigital)?StartGPUEngine()?{?fmt.Println("start?normal?gpu?engine")}func?(p?PS5WithDigital)?GetPrice()?int64?{?return?3600}那么除了這兩種基礎(chǔ)的產(chǎn)品類,廠商一般還會(huì)開發(fā)種主題限定配色的主、增加了硬件配置的機(jī)等等,這兩種在價(jià)上肯定會(huì)跟基礎(chǔ)版有不一樣,針對(duì)這種層的擴(kuò)展我們可以使用飾器來(lái)實(shí)現(xiàn),避免對(duì)礎(chǔ)組件類的更改。下是用兩個(gè)裝飾器實(shí)現(xiàn) Plus 版和主題配色版的兩個(gè)增蠪蚔。"本文使用的完整可運(yùn)源碼去公眾號(hào)「網(wǎng)管bi叨」發(fā)送【設(shè)計(jì)模式】即讙領(lǐng)取"http://?Plus?版的裝飾器func?(p?*PS5MachinePlus)?SetPS5Machine(ps5?PS5)?{?p.ps5Machine?=?ps5}func?(p?PS5MachinePlus)?StartGPUEngine()?{?p.ps5Machine.StartGPUEngine()?fmt.Println("start?plus?plugin")}func?(p?PS5MachinePlus)?GetPrice()?int64?{?return?p.ps5Machine.GetPrice()?+?500}//?主題色版的裝飾器type?PS5WithTopicColor?struct?{?ps5Machine?PS5}func?(p?*PS5WithTopicColor)?SetPS5Machine(ps5?PS5)?{?p.ps5Machine?=?ps5}func?(p?PS5WithTopicColor)?StartGPUEngine()?{?p.ps5Machine.StartGPUEngine()?fmt.Println("尊貴的主題色主機(jī),GPU啟動(dòng)")}func?(p?PS5WithTopicColor)?GetPrice()?int64?{?return?p.ps5Machine.GetPrice()?+?200}根據(jù)裝飾器模式的特論語(yǔ),兩個(gè)增強(qiáng)可以疊加在一起,組出即高配主題限定版機(jī)...... 呃,是不是有點(diǎn)某游海經(jīng)大每年發(fā)新機(jī)時(shí)給你的覺(jué)了,就是不出第二,每年給你多發(fā)幾個(gè)定配色、升級(jí)下屏幕說(shuō)的就是你 XXX(各位自己評(píng)論里腦補(bǔ)下)好了,在客戶端們把裝飾器和組件組起來(lái)就能獲得一款高主題限定版主機(jī)......"本文使用的完整可運(yùn)行源碼去公眾「網(wǎng)管叨bi叨」發(fā)送【設(shè)計(jì)模式】即陸山領(lǐng)"func?main()?{?ps5MachinePlus?:=?PS5MachinePlus{}?ps5MachinePlus.SetPS5Machine(PS5WithCD{})?//?ps5MachinePlus.SetPS5Machine(PS5WithDigital{})?//?可以在更換主機(jī)?ps5MachinePlus.StartGPUEngine()?price?:=?ps5MachinePlus.GetPrice()?fmt.Printf("PS5?CD?豪華Plus版,價(jià)格?%d?元\n\n",?price?ps5WithTopicColor?:=?PS5WithTopicColor{}?ps5WithTopicColor.SetPS5Machine(ps5MachinePlus)?ps5WithTopicColor.StartGPUEngine()?price?=?ps5WithTopicColor.GetPrice()?fmt.Printf("PS5?CD?豪華Plus?經(jīng)典主題配色版,價(jià)格?%d?元\n",?price}裝飾器和幾個(gè)模式的別裝飾器和代理在結(jié)上類似,在行為上跟責(zé)鏈模式類似,現(xiàn)在們總結(jié)一下他們之間區(qū)別裝飾器模式 VS 代理模式裝飾器模式就是代理模羅羅的一個(gè)殊應(yīng)用。裝飾器模式調(diào)自身功能的擴(kuò)展。理模式強(qiáng)調(diào)對(duì)代理過(guò)的控制。裝飾器 VS 職責(zé)鏈模式裝飾器和職責(zé)鏈在行為上螽槦都多個(gè)單元進(jìn)行組合完邏輯處理,但是裝飾注重給某樣?xùn)|西添加展,最終會(huì)得到一個(gè)品。而職責(zé)鏈更強(qiáng)調(diào)步驟完成某個(gè)流程,像是一個(gè)任務(wù)鏈表,且與裝飾器模式不同是,職責(zé)鏈可以隨時(shí)止。舉個(gè)例子來(lái)說(shuō),對(duì) OA 系統(tǒng)請(qǐng)假審批這個(gè)場(chǎng)景鬻子假設(shè)員請(qǐng)假需要得到組長(zhǎng)、監(jiān)和經(jīng)理的批準(zhǔn)才行在這種情況下,使用飾器模式實(shí)現(xiàn)的話無(wú)您的請(qǐng)假在前面的環(huán)被批準(zhǔn)還是被拒絕,個(gè)鏈條都不會(huì)中斷,終我們會(huì)得到三個(gè)級(jí)審批人對(duì)申請(qǐng)的全部饋。而使用職責(zé)鏈模的話,在每個(gè)階段,個(gè)審批人都有權(quán)批準(zhǔn)拒絕。如果請(qǐng)求在任級(jí)別被拒絕,那么整流程就會(huì)結(jié)束,請(qǐng)求會(huì)繼續(xù)流轉(zhuǎn)到下一個(gè)別的審批人那里。所看到這里,你覺(jué)得像 Web 框架的中間件這種東西應(yīng)該拿職責(zé)還是裝飾器實(shí)現(xiàn)呢?結(jié)裝飾器模式有不少點(diǎn),它是繼承的有力充,比繼承靈活,在改變?cè)袑?duì)象的情況,動(dòng)態(tài)地給一個(gè)對(duì)象展功能,即插即用。過(guò)使用不同裝飾類及些裝飾類的排列組合可以實(shí)現(xiàn)不同效果,全遵循程序設(shè)計(jì)的“閉原則”。但裝飾器使用必將會(huì)給程序帶更高的復(fù)雜性,更低可讀性,子類集成的碼結(jié)構(gòu)會(huì)更直白易懂些,而且雖然裝飾器合“開閉原則”,但它會(huì)給程序帶來(lái)更多類,動(dòng)態(tài)裝飾在多層飾時(shí)會(huì)更復(fù)雜。所以體上使用裝飾器模式時(shí)候也是兩害相較取輕,為了不頻繁修改經(jīng)成型的子類而引入多裝飾器類。應(yīng)用的候一定要謹(jǐn)記裝飾器“增強(qiáng)”某個(gè)事物用,可千萬(wàn)別把事物本實(shí)現(xiàn)的主邏輯用裝飾實(shí)現(xiàn)了。本文來(lái)自微公眾號(hào):網(wǎng)管叨 bi 叨 (ID:kevin_tech),作者:KevinYan11