<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>



      黃燜雞米飯最熱賣的外賣之一,國(guó)人都喜歡吃,吃過黃燜雞米飯的應(yīng)該都知道,除了黃燜雞米飯主體外,還可以添加各種配菜,如土豆、香菇、鵪鶉蛋、青菜等。如果需要你來設(shè)計(jì)一套黃燜雞米飯結(jié)賬系統(tǒng),你該如何設(shè)計(jì)呢?

      前置條件:主體:黃燜雞米飯 價(jià)格:16,配菜:土豆 價(jià)格:2、香菇 價(jià)格:2、鵪鶉蛋 價(jià)格:2、青菜 價(jià)格:1.5

      這還不簡(jiǎn)單?看我的,你隨手就來了下面這段代碼。
      public class HuangMenJiMiFan { // 黃燜雞價(jià)格 private double huangMenJiPrice = 16D;
      // 土豆價(jià)格 private double potatoPrice = 2D; // 鵪鶉蛋價(jià)格 private double eggPrice = 2D;
      // 香菇價(jià)格 private double mushroomPrice = 2D; // 青菜價(jià)格 private double vegPrice =
      1.5D; // 總價(jià)格 private double totalPrice = 0D; // 訂單描述 private StringBuilder desc
      = new StringBuilder("黃燜雞米飯 "); // 是否加土豆 private boolean hasPotato = false; //
      是否加鵪鶉蛋 private boolean hasEgg = false; // 是否加香菇 private boolean hasMushroom =
      false; // 是否加蔬菜 private boolean hasVeg = false; public HuangMenJiMiFan(){
      this.totalPrice = this.huangMenJiPrice; } public void setHasPotato(boolean
      hasPotato) { this.hasPotato = hasPotato; } public void setHasEgg(boolean
      hasEgg) { this.hasEgg = hasEgg; } public void setHasMushroom(boolean
      hasMushroom) { this.hasMushroom = hasMushroom; } public void setHasVeg(boolean
      hasVeg) { this.hasVeg = hasVeg; } public String getDesc(){ if (hasEgg){
      this.desc.append("+ 一份鵪鶉蛋 "); } if (hasMushroom){ this.desc.append("+ 一份香菇 ");
      } if (hasPotato){ this.desc.append("+ 一份土豆 "); } if (hasVeg){
      this.desc.append("+ 一份蔬菜 "); } return desc.toString(); } public double cost(){
      if (hasEgg){ this.totalPrice +=this.eggPrice; } if (hasMushroom){
      this.totalPrice +=this.mushroomPrice; } if (hasPotato){ this.totalPrice
      +=this.potatoPrice; } if (hasVeg){ this.totalPrice +=this.vegPrice; } return
      totalPrice; } }
      只要在點(diǎn)黃燜雞米飯的時(shí)候,把添加的配菜設(shè)置成true
      就好,這段代碼確實(shí)解決了黃燜雞米飯結(jié)算問題。但是我需要加兩份土豆呢?我需要添加一種新配菜呢?或者我新增一個(gè)黃燜排骨呢?這時(shí)候?qū)崿F(xiàn)起來就需要去改動(dòng)原來的代碼,這違背了設(shè)計(jì)模式的
      開放-關(guān)閉原則

      開放-關(guān)閉原則:類應(yīng)該對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉

      上面的設(shè)計(jì)違背了開放-關(guān)閉原則,為了避免這個(gè)問題,采用裝飾者模式似乎是一種可行的解決辦法。

      裝飾者模式:動(dòng)態(tài)的給一個(gè)對(duì)象添加一些額外的職責(zé),就增加功能來說,裝飾模式比生成子類更為靈活。

      裝飾者模式的通用類圖如下:

      從類圖中,我們可以看出裝飾者模式有四種角色:

      * Component:核心抽象類,裝飾者和被裝飾者都需要繼承這個(gè)抽象類
      * ConcreteComponent:對(duì)裝飾的對(duì)象,該類必須繼承Component
      * Decorator:裝飾者抽象類,抽象出具體裝飾者需要裝飾的接口
      * ConcreteDecorator:具體的裝飾者,該類必須繼承Decorator類,并且里面有一個(gè)變量指向Component抽象類
      裝飾者模式的核心概念我們都知道了,那就來實(shí)現(xiàn)一把,用裝飾者模式來設(shè)計(jì)黃燜雞米飯的結(jié)賬系統(tǒng)。

      Component類的設(shè)計(jì),仔細(xì)想想,不管黃燜雞米飯還是配菜都會(huì)涉及到金額計(jì)算。所以我們把該方法抽象到Component類。來設(shè)計(jì)我們黃燜雞米飯結(jié)賬系統(tǒng)的
      Component類,我們?nèi)∶凶鯢ood,Food類的具體設(shè)計(jì)如下:
      /** * 核心抽象類 */ public abstract class Food { String desc = "食物描述"; public
      String getDesc() { return this.desc; } // 價(jià)格計(jì)算 public abstract double cost(); }
      ConcreteComponent類是我們具體的被裝飾對(duì)象,我們這里的裝飾對(duì)象是黃燜雞米飯,我們來設(shè)計(jì)我們黃燜雞米飯的被裝飾對(duì)象Rice類,Rice
      類的具體實(shí)現(xiàn)如下:
      /** * 被裝飾者-黃燜雞米飯 */ public class Rice extends Food{ public Rice(){ this.desc
      ="黃燜雞米飯"; } @Override public double cost() { // 黃燜雞米飯的價(jià)格 return 16D; } }
      Decorator類是裝飾者的抽象類,我們需要定義一個(gè)getDesc()的抽象接口,因?yàn)樵贔ood類中,getDesc()
      不是抽象的,在后面的具體裝飾者中,需要重寫getDesc()類,所以我們需要將抽象在裝飾者這一層。我們來設(shè)計(jì)黃燜雞米飯結(jié)賬系統(tǒng)的裝飾者抽象類
      FoodDecorator,F(xiàn)oodDecorator類的具體設(shè)計(jì)如下:
      public abstract class FoodDecorator extends Food { // 獲取描述 public abstract
      String getDesc(); }
      ConcreteDecorator
      類是具體的裝飾者,我們有四個(gè)具體的裝飾者,分別是土豆、香菇、鵪鶉蛋、青菜,具體的裝飾者需要做的事情是計(jì)算出被裝飾者裝飾完裝飾品后的總價(jià)格和更新商品的描述。四個(gè)具體裝飾者的設(shè)計(jì)如下:
      public class Egg extends FoodDecorator { String desc = "雞蛋"; //
      存放Component對(duì)象,該對(duì)象可能是被裝飾后的 Food food; public Egg(Food food){ this.food = food; }
      // 計(jì)算總價(jià) 當(dāng)前Component對(duì)象的價(jià)格加上當(dāng)前裝飾者的價(jià)格 @Override public double cost() { return
      food.cost() + 2D; } @Override public String getDesc() { return food.getDesc()+"
      + "+this.desc; } } public class Mushroom extends FoodDecorator { String desc =
      "香菇"; Food food; public Mushroom(Food food){ this.food = food; } // 計(jì)算總價(jià)
      @Override public double cost() { return food.cost() + 2D; } @Override public
      String getDesc() { return food.getDesc()+" + "+this.desc; } } public class
      Potato extends FoodDecorator { String desc = "土豆"; Food food; public
      Potato(Food food){ this.food = food; } // 計(jì)算總價(jià) @Override public double cost() {
      return food.cost() + 2D; } @Override public String getDesc() { return
      food.getDesc()+" + "+this.desc; } } public class Veg extends FoodDecorator {
      String desc = "蔬菜"; Food food; public Veg(Food food){ this.food = food; }
      // 計(jì)算總價(jià) @Override public double cost() { return food.cost() + 1.5D; } @Override
      public String getDesc() { return food.getDesc()+" + "+this.desc; } }
      裝飾者的所有角色都實(shí)現(xiàn)完了,我們來測(cè)試一下使用裝飾者模式之后的黃燜雞結(jié)賬系統(tǒng),編寫一個(gè)App測(cè)試類。
      public class App { public static void main(String[] args) { // 點(diǎn)一份米飯 Rice rice
      = new Rice(); // 加個(gè)雞蛋 Egg egg = new Egg(rice); // 在加土豆 Potato potato = new
      Potato(egg); // 再加一份白菜 Veg veg = new Veg(potato);
      System.out.println(veg.getDesc()); System.out.println(veg.cost()); } }
      測(cè)試結(jié)果

      我們的描述和金額都是正確的,可能你還是沒怎么明白裝飾者模式,一起來看看我們的黃燜雞米飯被裝飾后的示意圖:



      我們的黃燜雞米飯共有三層裝飾,第一層是雞蛋,第二層是土豆,第三層是蔬菜。我們?cè)谧詈笳{(diào)用價(jià)格計(jì)算和商品描述都是調(diào)用了最外層的裝飾者的方法,有點(diǎn)像遞歸一樣,每一層的裝飾者都有被前一個(gè)裝飾者裝飾后的黃燜雞米飯對(duì)象。里面會(huì)產(chǎn)生想遞歸一樣的調(diào)用。希望看完這張圖之后,對(duì)你理解裝飾者模式有幫助。

      使用裝飾者模式之后的黃燜雞米飯結(jié)賬系統(tǒng),在新增配菜或者產(chǎn)品時(shí),我們不需要修改原先的功能,只需要對(duì)類進(jìn)行擴(kuò)展就好了,這完全遵循了開放-關(guān)閉原則。

      裝飾者模式的優(yōu)點(diǎn)

      * 裝飾類和被裝飾類可以獨(dú)立發(fā)展,而不會(huì)互相耦合,換句話說,就是Component類無須知道Decorator類,Decorator
      類也不用知道具體的被裝飾者。
      * 裝飾者模式是繼承關(guān)系的一個(gè)替代方案,從上面的黃燜雞米飯的案例中,我們可以看出,不管裝飾多少層,返回的對(duì)象還是Component
      * 裝飾者模式可以動(dòng)態(tài)的擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能
      裝飾者模式的優(yōu)點(diǎn)

      * 多層裝飾模式比較復(fù)雜,你可以想象一下剝洋蔥,如果最里面的裝飾出了問題,你的工作量會(huì)有多大?
      最后多說一句,JDK 中的 java.io 就是用裝飾者模式實(shí)現(xiàn)的,有興趣的可以去深入了解一下。

      源代碼 <https://github.com/BinaryBall/GOF23/tree/master/decorator>

      文章不足之處,望大家多多指點(diǎn),共同學(xué)習(xí),共同進(jìn)步

      最后

      打個(gè)小廣告,歡迎掃碼關(guān)注微信公眾號(hào):「平頭哥的技術(shù)博文」,一起進(jìn)步吧。

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

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          四个黑人玩一个少妇四p | 91少妇丨porny丨 | 国产A片网站 | 大香蕉综合久久 | 婷婷五月开心五月 | 亚洲人在线视频 | 小雪夹得又紧又舒服 | 新妺妺窝窝777777野外 | 成人影片中文字幕 | 日韩精品91偷拍在线观看 |