前言:對(duì)于設(shè)計(jì)模式我們有時(shí)候在想是否有必要,因?yàn)閷?shí)際開(kāi)發(fā)中我們沒(méi)有那么多閑工夫去套用這么多設(shè)計(jì)模式,也沒(méi)有必要為了模式而模式。

          通常這些模式會(huì)引入新的抽象層,增加代碼的復(fù)雜度,但是當(dāng)我們掌握了這些設(shè)計(jì)模式,

          在系統(tǒng)中比較棘手或者需要以后修改擴(kuò)展的地方采用了合適的設(shè)計(jì)模式會(huì)讓我們的系統(tǒng)易于擴(kuò)展維護(hù)甚至工作變得輕松很多。

          對(duì)于這一點(diǎn)我深有體會(huì),有時(shí)候設(shè)計(jì)的比較好的功能模塊在后來(lái)客戶(hù)改變需求的時(shí)候變得很容易且方便添加修改。

          但是如果比較糟糕偷懶的方式會(huì)讓我們對(duì)自己的代碼修改變得害怕,害怕客戶(hù)提需求,害怕去動(dòng)自己的代碼。

          所以對(duì)于框架或者這些設(shè)計(jì)模式我們可以不用過(guò)度使用,但是要用的時(shí)候能有儲(chǔ)備或者腦袋里面會(huì)閃現(xiàn)出對(duì)應(yīng)的解決方案。

          這樣不光會(huì)提升我們的編碼興趣對(duì)我們開(kāi)發(fā)的產(chǎn)品也更有信心。

          本篇就聚焦Head First設(shè)計(jì)模式中的裝飾者模式進(jìn)行學(xué)習(xí)和總結(jié)。

          咖啡店結(jié)算案例

          咖啡店賣(mài)各種咖啡,根據(jù)調(diào)料不一樣就會(huì)有不同價(jià)格的咖啡飲品可選,那么對(duì)應(yīng)的咖啡飲品價(jià)格也不一樣。

          咖啡是需要按照基礎(chǔ)價(jià)格+調(diào)料組合計(jì)算價(jià)格的,那按照繼承的方式我們抽象一個(gè)飲料基類(lèi)Beverage,Beverage擁有Cost抽象方法用于計(jì)算價(jià)格。

          其他咖啡飲品繼承Beverage實(shí)現(xiàn)Cost方法根據(jù)自己的調(diào)料計(jì)算價(jià)格。
          public abstract class Beverage { public abstract void Description(); public
          abstract float Cost(); } public class DarkRoast : Beverage { public override
          void Description() { //深焙咖啡 } public override float Cost() { //各種調(diào)料價(jià)格計(jì)算 } }
          對(duì)于繼承的方式,其他子類(lèi)都要去實(shí)現(xiàn)一遍價(jià)格計(jì)算無(wú)法復(fù)用,如果子類(lèi)比較多那么繼承的子類(lèi)會(huì)“爆炸”,新增加子類(lèi)對(duì)于我們來(lái)說(shuō)就是一項(xiàng)重復(fù)工作。

          如果說(shuō)某一種調(diào)料的價(jià)格變化我們還得去每個(gè)子類(lèi)里面改變價(jià)格。

          那我們針對(duì)變化的調(diào)料部分是不是讓他們按照實(shí)際需求組合,在子類(lèi)中確定自己加哪些調(diào)料就行了,似乎這種方式會(huì)減少重寫(xiě)和維護(hù)難度。

          按照這個(gè)思路將Beverage改造,將是否有調(diào)料定義成變量,然后Cost方法不再抽象而是提供實(shí)現(xiàn)。
          public abstract class Beverage { //牛奶 public bool Milk { get; set; } //糖
          public bool Suger { get; set; } //摩卡 public bool Mocha { get; set; } public
          abstract void Description(); public virtual float Cost() { float price = 0; if
          (Milk) { price += 1; } if (Suger) { price += 2; } if (Mocha) { price += 3; }
          return price; } } public class DarkRoast : Beverage { public override void
          Description() { Console.WriteLine("深焙咖啡"); } public override float Cost() {
          Milk = true; Suger = true; return 1.1f+base.Cost(); } }
            

          ?

          ?

          ?

          這種方式比之前的繼承的確好了許多,不過(guò)還是有如下幾個(gè)問(wèn)題:

          1、調(diào)料價(jià)格改變會(huì)使我們改變現(xiàn)有代碼。

          2、需要添加新的調(diào)料,我們就需要添加新的方法并改變Beverage基類(lèi)的Cost方法。

          3、某些調(diào)料可能并不適合其他飲品,例如茶還要繼承這些不屬于它的調(diào)料。

          4、如果顧客需要雙份糖,Cost方法就會(huì)失效。

          接下來(lái)我們就用"裝飾者模式"來(lái)更好的設(shè)計(jì)該案例。

          認(rèn)識(shí)裝飾者模式

          這里有一個(gè)設(shè)計(jì)模式很重要的設(shè)計(jì)原則:類(lèi)應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉(開(kāi)閉原則)

          裝飾模式同樣遵循開(kāi)閉原則。

          對(duì)于咖啡店來(lái)說(shuō),主體是飲料不變,變化的是調(diào)料。我們以飲料為主體,其他調(diào)料來(lái)“裝飾”飲料。比如顧客想要加了Mocha(摩卡)的
          DarkRoast(深焙咖啡),我們要做的是:

          1、制造一個(gè)DarkRoast對(duì)象

          2、以Mocha(摩卡)對(duì)象裝飾它

          3、調(diào)用Cost()方法,并依賴(lài)委托(非C# delegate,只是概念)將調(diào)料的價(jià)錢(qián)加上去



          利用裝飾者模式

          首先我們修改主體飲料Beverage基類(lèi),GetDescription 返回描述,Cost由子類(lèi)自己實(shí)現(xiàn)定價(jià)。

          ?
          public abstract class Beverage { string description = "Unkonwn Beverage";
          public virtual string GetDescription() { return description; } public abstract
          float Cost(); }
          深焙咖啡類(lèi)
          public class DarkRoast : Beverage { public DarkRoast() { description =
          "深焙咖啡"; } public override float Cost() { return 1.1f; } }
          裝飾類(lèi)我們定義一個(gè)抽象基類(lèi)Condiment(調(diào)料)并繼承Beverage。

          為什么要定義一個(gè)抽象裝飾基類(lèi),因?yàn)檠b飾類(lèi)可能需要抽象出其他方法,而且因?yàn)槲覀冇醚b飾類(lèi)去裝飾了被裝飾者后 我們本身也應(yīng)該變成可已讓別人裝飾的類(lèi)。
          所以裝飾類(lèi)繼承CondimentDecorator,CondimentDecorator繼承的是Beverage。此例暫未加入裝飾類(lèi)擁有的屬性和方法
          public abstract class CondimentDecorator:Beverage { }
          我們?cè)賹?shí)現(xiàn)兩個(gè)裝飾類(lèi):Mik和Suger,用變量記錄被裝飾者,在構(gòu)造函數(shù)里面設(shè)置被裝飾者。
          public class Milk : CondimentDecorator { //用變量記錄被裝飾者 Beverage beverage;
          public Milk(Beverage beverage) { this.beverage = beverage; } public override
          string GetDescription() { return beverage.GetDescription() + "+Milk"; } public
          override float Cost() { return beverage.Cost() + 1; } } public class Suger :
          CondimentDecorator { //用變量記錄被裝飾者 Beverage beverage; public Suger(Beverage
          beverage) { this.beverage = beverage; } public override string GetDescription()
          { return beverage.GetDescription() + "+Suger"; } public override float Cost() {
          return beverage.Cost() + 2; } }
          編寫(xiě)測(cè)試結(jié)果:



          ?

          ?

          ?總結(jié)

          裝飾者模式說(shuō)明:動(dòng)態(tài)地將責(zé)任附加到對(duì)象上。若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案。

          畫(huà)出本例中裝飾者模式類(lèi)圖以便理解和記憶



          ?

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問(wèn)題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                乱伦91 | 日韩日屄视频 | 中文字幕乱码在线蜜乳欧美字幕 | 四虎一区二区 | 亚洲狼人综合 |