Java裝飾者模式

C_0006.gifHello,即將要寫的這篇文章,是對剛剛學習完的裝飾者模式的一個總結啦,也不是什麼技術難點,就是鞏固一下啦。i_f47.gifi_f47.gif


一.裝飾者模式的定義

    裝飾者模式動態的將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。

    只看定義真的有些不明白,先簡單說明一下,下面還有例子呢。

    (1)定義中提到了繼承,看來裝飾者模式是來解決擴展功能時使用繼承的不足的;

    (2)可以做到運行時裝飾類,給對象賦予新的職責。

    (3)還是看下面的例子吧。


二.實例--飲品店

    飲品店裏有,飲品--咖啡、果汁、茶類,飲品中可以加不同的配料--摩卡、牛奶、糖、奶泡;不同的飲品加上不同的配料有不同的價錢,怎樣實現呢?

    方式一:單純的繼承

    最突出的缺點--造成類爆炸(組合的種類太多);

    方式二:使用裝飾者模式

    1.裝飾者模式的組成:抽象組件(Beverage)、具體組件(Coffee、Tea等)、抽象裝飾者(IngredientDecorator)、具體裝飾者(Mocha、Milk等),以例子說明的關係圖如下:

wKiom1ZT3GCSIJuKAAB0CVE5avU318.png

    2.代碼示例:

        抽象組件--超類--Beverage:

    

        public abstract class Beverage {        
            //description實例變量表示不同的描述,由子類賦值使用
            String description = "Uknown Beverage";
        
            public String getDescription() {
                return description;
            }
            
            //抽象方法,由子類實現
            public abstract double cost();
        }

        具體組件--B_Coffee、B_FruitJuice等:

        public class B_Coffee extends Beverage{        
            
            /**
             * 在構造器中設置飲料的描述
             */
            public B_Coffee(){
                description = Description.COFFEE;
            }
        
            /**
             * 實現父類--抽象組件中的抽象方法
             * 計算該飲料的價錢
             */
            public double cost() {
                return Cost.COFFEE;
            }
        
        }
        public class B_FruitJuice extends Beverage{        
            public B_FruitJuice(){
                description = Description.FRUIT_JUICE;
            }
        
            public double cost() {
                return Cost.FRUIT_JUICE;
            }
        
        }

        抽象裝飾者--IngredientDecorator:

        /**        
         * 繼承的目的是爲了IngredientDecorator能夠取代Beverage
         * @author wangzhaoli
         *
         */
        public abstract class IngredientDecorator extends Beverage{
            /**
             * IngredientDecorator中覆蓋父類中的getDescription()方法
             * 繼承IngredientDecorator的所有觀察者需各自實現
             */
            public abstract String getDescription();
        }

        具體裝飾者們--C_Mocha、C_Milk等:

        /**        
         * C_Mocha是一個裝飾者
         * C_Mocha繼承的CondimentDecorator
         * CondimentDecorator繼承了Beverage
         * @author wangzhaoli
         *
         */
        public class C_Mocha extends IngredientDecorator{
            
            /**
             * 要讓C_Mocha能夠引用一個Beverage,做法是:
             * 1.用一個實例變量記錄Beverage,也就是被裝飾者;
             * 2.想辦法讓Beverage被記錄到實例變量中,即構造器參數實例化。
             */
            private Beverage beverage;
            
            public C_Mocha(Beverage beverage){
                this.beverage = beverage;
            }
        
            /**
             * 實現父類CondimentDecorator中的抽象方法
             */
            public String getDescription() {
                //利用委託的方法得到之前的描述
                return beverage.getDescription() + "," + Description.MOCHA;
            }
        
            /**
             * 實現父類的父類Beverage中的抽象方法
             */
            public double cost() {
                return beverage.cost() + Cost.MOCHA;
            }
        
        }
        public class C_Milk  extends IngredientDecorator{        
            
            private Beverage beverage;
            
            public C_Milk(Beverage beverage){
                this.beverage = beverage;
            }
        
            public String getDescription() {
                return beverage.getDescription() + "," + Description.MILK;
            }
        
            public double cost() {
                return beverage.cost() + Cost.MILK;
            }
        
        }

        測試類--main:

        public class MainTest {        
            public static void main(String[] args) {
                Beverage fruitJuice = new B_FruitJuice();
                System.out.println(fruitJuice.getDescription()+":"+fruitJuice.cost());
                System.out.println();
                
                Beverage coffee = new B_Coffee();
                coffee = new C_Mocha(new C_Mocha(new C_Suger(coffee)));
                System.out.println(coffee.getDescription()+":"+coffee.cost());
                System.out.println();
                
                Beverage tea = new B_Tea();
                tea = new C_Mocha(tea);
                tea = new C_Milk(tea);
                tea = new C_Suger(tea);
                tea = new C_Form(tea);
                System.out.println(tea.getDescription()+":"+tea.cost());
                System.out.println();
            }
        
        }

        測試結果:

        Fruit Juice:8.0        
        
        Coffee,Suger,Mocha,Mocha:9.5
        
        Tea,Mocha,Milk,Suger,Form:9.5

二.由實例說明裝飾者模式 

    1.裝飾者模式中很好的體現了組合(composition)和委託(delegation):
        (1)利用繼承設計子類的行爲是在編譯時靜態決定的,利用組合的做法擴展對象的行爲可以在運                    行時動態的進行擴展
        (2)利用繼承達到"類型匹配",而不是獲得"行爲",新的行爲是由"組合對象"得來的;
        (3)利用組合和委託可以實現在運行時具有繼承的效果;

    2.裝飾者模式完全遵循"開放--關閉原則":類應該對擴展開放,對修改關閉。
    3.以例子說明裝飾者的使用:
       拿一個咖啡對象,用摩卡裝飾它,再用牛奶裝飾它,然後調用cost()方法,並依賴委託                     (delegate)將各種配料的價格加上去。

    4.每個具體的組件都可以單獨使用,或者被裝飾者包裝起來動態的加上新行爲使用;
    5.裝飾者與抽象組件是"有一個"的關係,所以需要在每一個具體裝飾者中定義一個實例變量以保存
       某個具體組件的引用;
    6.裝飾者的新行爲是指:通過在舊行爲前面/後面加上一些計算、拼接等處理;

    7.裝飾者和被裝飾者對象有相同的超類型;

    8.可以用一個或多個裝飾者包裝一個對象;

    9.裝飾者可以所委託被裝飾者的行爲之前/之後,加上自己的行爲,以達到指定的目的;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章