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.装饰者可以所委托被装饰者的行为之前/之后,加上自己的行为,以达到指定的目的;

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