<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    合工大很牛很牛牛

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      14 Posts :: 1 Stories :: 37 Comments :: 0 Trackbacks

     

    一個旅館提供各種飲料(Beverage), 比如有HouseBlendDarkRoast等,每個飲料還有很多配料比如MilkSoy等。如何寫一個程序能夠方便的輸出每種飲料的價格呢?(包括飲料+配料)

     

    最笨的方法如下:也就是每種飲料,每種飲料加配料的組合,都寫一個類。

    package javaapplication33;

     

    public class Main {

        public static void main(String[] args) {

            Beverage b=new HouseBlendWithMilk();

            System.out.println(b.getDescription());

            System.out.println(b.cost());

        }

    }

     

    abstract class Beverage {

        public abstract String getDescription();

        public abstract int cost();

    }

     

    class HouseBlend extends Beverage {

        @Override

        public String getDescription() {

            return "A cup of HouseBlend";

        }

        @Override

        public int cost() {

            return 10;

        }

    }

     

    class DarkRoast extends Beverage {

        @Override

        public String getDescription() {

            return "A cup of DarkRoast";

        }

        @Override

        public int cost() {

            return 8;

        }

    }

     

    class HouseBlendWithMilk extends Beverage{

        @Override

        public String getDescription() {

            return "A cup of HouseBlend with a soap of milk.";

        }

        @Override

        public int cost() {

           return 12;

        }

       

    }

     

    問題來了,如果飲料及其配料的排列組合有20種,30種,這很可能。那么是不是就要繼承Beverage寫上2030個類呢?這倒不是關鍵,比如萬一Milk的價格變動了,那么所有有關Milk的類都要把cost()方法重寫。。。。這才恐怖呢。原因是我們沒有把變化的部分封裝起來。

     

    OK,我們開始封裝。為方便起見,我們仍把主要的飲料HouseBlend, DarkRoast等寫成父類Beverage的子類。我們把造成變化的配料MilkSoy等把它們封裝起來,封裝到哪?封裝到父類里面去。看看下面這樣行不行:

    package javaapplication33;

     

    public class Main {

        public static void main(String[] args) {

            Beverage b = new HouseBlend();

            b.setMilk(true); //增加一個配料

            System.out.println(b.cost());

            b.setSoy(true);

            System.out.println(b.getDescription());

            System.out.println(b.cost());

            b.setMilk(false);

            System.out.println(b.cost());

            b.setSoy(false);

            System.out.println(b.cost());

            System.out.println(b.getDescription());

        }

    }

     

    abstract class Beverage {

        int MILKPRICE = 2;

        int SOYPRICE = 3;

        public boolean milk;

        public boolean soy;

        int cost;

        String description;

        public void setMilk(boolean b) {

            milk = b;

        }

        public void setSoy(boolean b) {

            soy = b;

        }

        public int cost() {

            cost = 0;

            if (milk) {

                cost += MILKPRICE;

            }

            if (soy) {

                cost += SOYPRICE;

            }

            return cost;

        }

        public String getDescription() {

            description = "";

            if (milk) {

                description += " with a soap of milk";

            }

            if (soy) {

                description += " with a bottle of soy";

            }

            return description;

        }

    }

     

    class HouseBlend extends Beverage {

        @Override

        public String getDescription() {

            return "a cup of HouseBlend" + super.getDescription();

        }

        @Override

        public int cost() {

            return super.cost() + 10;

        }

    }

     

    class DarkRoast extends Beverage {

        @Override

        public String getDescription() {

            return "a cup of DarkRoast" + super.getDescription();

        }

        @Override

        public int cost() {

            return super.cost() + 8;

        }

    }

     

    這樣,每當我需要一個飲料加幾個配料時,僅需要new這個飲料,再set配料即可。貌似這個程序沒問題了。

     

    貌似!

    (1)      當配料的價格改動時,Beverage這個類需要改動。設計模式的原則是在提供擴展的同時,盡可能不改動原有的程序的。

    (2)       如果新增,或者減少某幾種配料,同理,Beverage仍需改動。    

    (3)       如果我們要雙份的Milk呢?

    崩潰!

     

    以上,第一種思路是把所有的排列組合都寫成子類,當一個配料變動,會導致所有相關的組合都要變動。

    第二種思路是把飲料寫成子類,配料的設置封裝到父類中去,當配料變動時,會導致原有的父類變動,并且無法同時提供兩份同樣的配料。

     

    其實當第一種思路被否定掉的時候就有一種沖動,就是把飲料和配料都寫成子類,繼承抽象的父類Beverage。這個其實很容易做到。只是主程序在調用時,比如我要一個HouseBlend配上Milk的時候,我該怎么生成呢?new一個HouseBlend,再new一個Milk,然后呢?怎么讓它打印出“A Houseblend with a cup of milk”這樣,并且算價格的時候直接兩者的cost就能疊加呢?

     

    我們想到了在讀寫文件操作時的樣子: new XXX(new XXX(new XXXXX())); 如果飲料加上配料可以這樣生成,豈不是全都解決了?

     

    package javaapplication32;

     

    public class Main {

        public static void main(String[] args) {

            Baverage b = new Milk(new HouseBland(new Soy()));

            System.out.println(b.getDescription());

            System.out.println(b.getCost());

        }

    }

     

    abstract class Baverage {

        abstract String getDescription();

        abstract int getCost();

    }

     

    class HouseBland extends Baverage {

        Baverage baverage;

        HouseBland() {

        }

        HouseBland(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return "A cup of HouseBland" + baverage.getDescription();

            }

            else {

                return "A cup of HouseBland";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return 10 + baverage.getCost();

            }

            else {

                return 10;

            }

        }

    }

     

    class Milk extends Baverage {

        Baverage baverage;

        Milk() {

        }

        Milk(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return baverage.getDescription() + " And a soap Milk";

            }

            else {

                return " And a soap Milk";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return baverage.getCost() + 5;

            }

            else {

                return 5;

            }

        }

    }

     

    class Soy extends Baverage {

        Baverage baverage;

        Soy() {

        }

        Soy(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return baverage.getDescription() + " And a bottle of Soy";

            }

            else {

                return " And a bottle of Soy";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return baverage.getCost() + 7;

            }

            else {

                return 7;

            }

        }

    }

     

    問題解決了?可不可以更完美呢?我們發現每一個子類里面都用了大量的判斷語句 

    if (baverage != null) {…..} else {…..}

    幾乎都是一樣的,為什么每個都要寫呢?原因是我們沒有人為的規定Baverage b = new Milk(new HouseBland(new Soy()));這個語句的順序。是“配料(new 飲料()) 還是“飲料(new 配料)”?如果我們規定一下順序的話,就有很多前面的if判斷語句不需要反復寫。

     

    這個改進看起來好像不重要,但是,在實際工作中,像HouseBlend這樣的類就像是原先寫好的類,或者幾乎長時間不會改變的類;而想配料Milk這樣的類,就如同經常改動或者新增進去的類。也就是說前者不怎么改動,而后者會經常變。那么我們就要盡量保證前者的穩定和簡單(越簡單越不易出錯)。

     

    下面的程序,我們刪除了HouseBlend中的繁雜的判斷語句,在主函數生成飲料加配料時,我們要保證“new 配料(new 配料(….(new 飲料())))的模式(先配料后飲料)。(因為一個飲料可以配多個配料而一個配料不可以配多個飲料)

    源代碼如下:

    package javaapplication32;

     

    public class Main {

        public static void main(String[] args) {

            Baverage b = new Milk(new Soy(new HouseBlend()));

            System.out.println(b.getDescription());

            System.out.println(b.getCost());

        }

    }

     

    abstract class Baverage {

        abstract String getDescription();

        abstract int getCost();

    }

     

    class HouseBlend extends Baverage {

        @Override

        String getDescription() {

     

            return "A cup of HouseBland";

        }

        @Override

        int getCost() {

            return 10;

        }

    }

     

    class Milk extends Baverage {

        Baverage baverage;

        Milk() {

        }

        Milk(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return baverage.getDescription() + " And a soap Milk";

            }

            else {

                return " And a soap Milk";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return baverage.getCost() + 5;

            }

            else {

                return 5;

            }

        }

    }

     

    class Soy extends Baverage {

        Baverage baverage;

        Soy() {

        }

        Soy(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return baverage.getDescription() + " And a bottle of Soy";

            }

            else {

                return " And a bottle of Soy";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return baverage.getCost() + 7;

            }

            else {

                return 7;

            }

        }

    }

     

    其實我們還沒揭示Decorator pattern的核心含義:配料跟主料其實不是一回事,但是為了實現主料的新功能,又要保持主料的穩定,我們就用配料繼承主料,或者繼承主料的父函數,目的就是獲得相通的類型(type match)。

    這樣,我們可以在其他程序調用時,隨時給主料添加配料的新功能。這就是composition組合的魅力!

     

    最后,我們對上面的程序做一下最終的改進,原因是由于在類的層次設計的時候,我們沒有區分飲料和配料之間的關系,因為它們都平行的繼承了同一個抽象類。在Decorator pattern里面,往往會出現這樣的情況:就是飲料的種類很穩定,而配料的種類卻很繁雜。為了讓程序看上去更清晰(一眼就能看出誰是主,誰是配),我們用特定的一個抽象類繼承原先的父類,再讓所有的配料繼承該抽象類。

     

    package javaapplication32;

     

    public class Main {

        public static void main(String[] args) {

            Baverage b = new Milk(new Soy(new HouseBlend()));

            System.out.println(b.getDescription());

            System.out.println(b.getCost());

        }

    }

     

    abstract class Baverage {

        abstract String getDescription();

        abstract int getCost();

    }

     

    class HouseBlend extends Baverage {

        @Override

        String getDescription() {

     

            return "A cup of HouseBland";

        }

        @Override

        int getCost() {

            return 10;

        }

    }

     

    abstract class Decorator extends Baverage {

        abstract String getDescription();

        abstract int getCost();

    }

     

    class Milk extends Decorator {

        Baverage baverage;

        Milk() {

        }

        Milk(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return baverage.getDescription() + " And a soap Milk";

            }

            else {

                return " And a soap Milk";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return baverage.getCost() + 5;

            }

            else {

                return 5;

            }

        }

    }

     

    class Soy extends Decorator {

        Baverage baverage;

        Soy() {

        }

        Soy(Baverage baverage) {

            this.baverage = baverage;

        }

        @Override

        String getDescription() {

            if (baverage != null) {

                return baverage.getDescription() + " And a bottle of Soy";

            }

            else {

                return " And a bottle of Soy";

            }

        }

        @Override

        int getCost() {

            if (baverage != null) {

                return baverage.getCost() + 7;

            }

            else {

                return 7;

            }

        }

    }

     

    其實java API里面有很多使用Decorator Pattern的例子,比如讀寫文件:

    posted on 2008-07-04 10:59 化的了 閱讀(945) 評論(1)  編輯  收藏 所屬分類: 設計模式

    Feedback

    # re: 配件模式 Decorator Pattern 2008-07-04 13:13
    寫得很好。
    受益了。  回復  更多評論
      

    主站蜘蛛池模板: 99精品视频免费观看| ssswww日本免费网站片| 亚洲综合免费视频| 91久久亚洲国产成人精品性色| 在线看片免费人成视频播| 亚洲精品亚洲人成在线观看| 99久久国产精品免费一区二区| 亚洲国产精品久久66| h视频在线免费看| 亚洲日本中文字幕天天更新| 德国女人一级毛片免费| 另类小说亚洲色图| 久久亚洲精品无码播放| 久久精品成人免费观看| 亚洲黄色在线观看视频| 成年女人毛片免费播放人| 粉色视频在线观看www免费| 国产精品亚洲产品一区二区三区 | 亚洲理论电影在线观看| 一级毛片全部免费播放| 性xxxx黑人与亚洲| www国产亚洲精品久久久| 岛国精品一区免费视频在线观看| 久久精品国产亚洲AV麻豆~ | 拨牐拨牐x8免费| 香港经典a毛片免费观看看| 国产精品亚洲精品日韩已满| 91成人在线免费视频| 亚洲免费网站观看视频| 国产亚洲色视频在线| 99久久精品日本一区二区免费| 苍井空亚洲精品AA片在线播放 | 国产又黄又爽又猛免费app| 亚洲aⅴ无码专区在线观看| 色噜噜AV亚洲色一区二区| 1000部拍拍拍18免费网站| 特色特黄a毛片高清免费观看| 亚洲精选在线观看| 在线日韩av永久免费观看| 免费日本一区二区| 亚洲AV成人无码久久WWW|