设计模式之 装饰者模式(Decorator Pattern)

装饰者模式(Decorator Pattern)

关于装饰者模式,举个简单的例子来说明它的实现方式。

需求

大家在购买咖啡的时候,往往会依据自己的口味要求店员在咖啡中添加各种调料,例如:豆浆(Soy)、摩卡(Mocha,也就是巧克力风味)、奶泡(Whip)等。店员会根据所加入的调料而收取不同的费用。那么,使用面向对象编程,如何让这种需求变得可拓展呢?
问题难点在于:由于各种调料和各种咖啡的搭配不同,排列组合会有许多中品类产生,此时装饰者模式在这种场景下会大显身手。
看一个具体实现:

摩卡加奶泡的深焙咖啡

以咖啡饮料为主体,然后在运行时以调料来“装饰”(decorate)咖啡饮料。比如顾客想来一杯摩卡加奶泡的深焙咖啡,那么,实现思路如下:

  1. 拿一个深焙咖啡(DarkRoast)对象
  2. 以摩卡(Mocha)对象装饰它
  3. 以奶泡(Whip)对象装饰它
  4. 调用cost()方法,并依赖委托(delegate)将调料的价钱加上去

总体设计图

在这里插入图片描述

装饰者模式动态地将责任附加到对象上,若要拓展功能,装饰者提供了比继承更有弹性到替代方案。

代码实现

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:21
 * 饮料抽象类
 */

public abstract class Beverage {
    String description="Unknown Beverage";

    public String getDescription(){
        return description;
    }

    public abstract  double cost();

}

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:23
 * 调料抽象类
 *
 * 必须让Condiment Decorator能够取代Beverage,所以将Condiment Decorator拓展自Beverage类
 */

public abstract class CondimentDecorator extends Beverage {
    //所有的调料装饰者都必须重新实现getDescription()方法
    public abstract String getDescription();
}

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:29
 *
 * 浓缩咖啡
 * 是一种饮料,拓展自Beverage(饮料类)
 */

public class Espresso extends Beverage {

    public Espresso(){
        description="Espresso";//为了要设置饮料的描述,我们写了一个构造器。description实例遍历继承自Beverage
    }



    @Override
    public double cost() {
        //要计算Espresso的价钱
        return 1.99;
    }
}

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:33
 * 另一种饮料,做法和Espresso一样,名称不同
 *
 */

public class HouseBlend extends Beverage {

    public HouseBlend(){
        description="House Blend Coffee ";
    }
    @Override
    public double cost() {
        return 0.89;
    }
}

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:35
 *
 * 摩卡
 * 装饰者
 */

public class Mocha extends CondimentDecorator {

    //用一个实例记录饮料,也就是被装饰者
    Beverage beverage;

    public Mocha(Beverage beverage){
        //要让Mocha能够引用一个Beverage
        //1.用一个实例变量记录饮料,也就是被装饰者
        //2.想办法让被装饰者(饮料)被记录到实例变量中,这里的做法是:把饮料当作构造器的参数。再有构造器将饮料
        //记录在实例变量中
        this.beverage=beverage;

    }

    public String getDescription(){
        //我们希望叙述不只是描述饮料(例如"DarkRost"),而是完整得连调料都描述出来,(例如"DarkRost,Macha")
        //所以首先需要利用委托的做法,得到一个叙述,然后在其后加上附加的叙述(例如"Mocha")
        return beverage.getDescription()+",Mocha";

    }


    public double cost(){
        //要计算带Mocha饮料的钱。首先把调用委托给被装饰对象,以计算价钱,然后再加上Mocha的钱,得到足后结果。
        return .20+beverage.cost();
    }

}

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:48
 *
 * Soy调料
 */

public class Soy extends CondimentDecorator {

    Beverage beverage;

    public Soy(Beverage beverage){
        this.beverage=beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription()+",Soy";
    }

    public double cost(){
        return .77+beverage.cost();
    }
}

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:50
 *
 * Whip 调料
 */

public class Whip extends CondimentDecorator {
    Beverage beverage;

    public Whip(Beverage beverage){

        this.beverage=beverage;

    }

    @Override
    public String getDescription() {
        return beverage.getDescription()+",Whip";
    }

    public double cost(){
        return beverage.cost()+.99;
    }
}

压轴测试类,开始享受一杯自己喜欢的咖啡吧!

package decorator;

/**
 * @author zhangjinglong
 * @date 2019-11-13-20:52
 *
 * 测试类
 * 开始享受一杯咖啡
 */

public class StartbuzzCoffee {

    public static void main(String[] args) {
        Beverage beverage=new Espresso();//订一杯Espresso,不需要调料,打印出它的描述与价格

        System.out.println(beverage.getDescription()+"  $"+beverage.cost());


        Beverage beverage2=new HouseBlend();//创建一个HouseBlend对象
        beverage2=new Mocha(beverage2);//用Mocha装饰它
        beverage2=new Soy(beverage2);//用Soy装饰它
        beverage2=new Whip(beverage2);//用Whip装饰它

        System.out.println(beverage2.getDescription()+"  $"+beverage2.cost());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值