装饰模式 Decorator Pattern

场景描述:

一个咖啡店,有多种咖啡、多种配料,它们相互组合,配置成一杯咖啡,不同组合价格不同。目前有四种咖啡,分别是HouseBlend(混合咖啡)、DarkRoast(深度烘焙 )、Decaf(无咖啡因)、Espresso(浓咖啡)。配料有milk、soy(豆浆)、Mocha(摩卡)、whip(奶泡)。购买咖啡时选择一种咖啡,多种配置组合。

原本的类图如下,我们要对它进行改造。


问题:

看到上面的类图,如果购买时增加配料要如何计算价格呢,这次本次设计的关键问题。根据开闭原则,我们要对扩展开放,对修改关闭,意思是增加功能时应该是增加新的代码,而不应该修改现在的代码。所以尽量不要更改现在代码,降低引入新bug的风险。可以有这样一个解决方案,在现有的Beverage中加入配料的属性,保存存在的配料集合,这样就能计算价格。但是这个方案违反了开闭原则,使用装饰模式能帮我们避免这个问题。


使用装饰模式计算价格的流程:

需求:顾客需要一杯加了Mocha(摩卡)和whip(奶泡)的DarkRoast咖啡。


计算价格:


其实就是递归调用,从底层开始返回,并相加,得出最后的价格。


装饰模式:

在使用装饰模式实现本次例子前,我们先来了解一下装饰模式。

定义:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

类图:


具体实现:

部分代码没贴上来,代码地址:https://github.com/LiuJinan/designPatternDemo

/**
 * Created by LiuJinan on 2017/7/1.
 */
// 属于类图中的Component 组件
public interface Berverage {

    public String getDescription();

    public double cost();
}


/**
 * Created by LiuJinan on 2017/7/1.
 */
//可被装饰的具体组件
public class DarkRoast implements Berverage {
    @Override
    public String getDescription() {
        return "DarkRoast ";
    }

    @Override
    public double cost() {
        return 9;
    }
}


//可被装饰的具体组件
public class HouseBlend implements Berverage {
    @Override
    public String getDescription() {
        return "HouseBlend ";
    }

    @Override
    public double cost() {
        return 10;
    }
}

//所有配料装饰者的父类
public interface CondimentDecorator extends Berverage {

}

//装饰者:牛奶
public class Milk implements CondimentDecorator {

    private Berverage berverage;

    public Milk(Berverage berverage) {
        this.berverage = berverage;
    }

    @Override
    public String getDescription() {
        return berverage.getDescription() + ", milk";
    }

    @Override
    public double cost() {
        return berverage.cost() + 1.5; //milk  1.5元
    }
}

//装饰者:Mocha
public class Mocha implements CondimentDecorator {

    private Berverage berverage;

    public Mocha(Berverage berverage) {
        this.berverage = berverage;
    }

    @Override
    public String getDescription() {
        return berverage.getDescription() + ", Mocha";
    }

    @Override
    public double cost() {
        return berverage.cost() + 2;    //Mocha 2元
    }
}

//装饰者:豆浆
public class Soy implements CondimentDecorator {

    private Berverage berverage;

    public Soy(Berverage berverage) {
        this.berverage = berverage;
    }

    @Override
    public String getDescription() {
        return berverage.getDescription() + ", soy";
    }

    @Override
    public double cost() {
        return berverage.cost() + 1;    //豆浆 1元
    }
}

//装饰者:奶盖
public class Whip implements CondimentDecorator {

    private Berverage berverage;

    public Whip(Berverage berverage) {
        this.berverage = berverage;
    }

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

    @Override
    public double cost() {
        return berverage.cost() + 3;    //Whip 3元
    }
}

运行结果:

public static void main(String[] args) {

        //1.买一杯加了奶盖的混合咖啡
        Berverage houseBlend = new HouseBlend();
        houseBlend = new Whip(houseBlend);
        System.out.println(houseBlend.getDescription() + " " + houseBlend.cost());

        //2.买一杯加了摩卡和豆浆的深度烘焙
        Berverage darkRoast = new DarkRoast();
        darkRoast = new Mocha(darkRoast);
        darkRoast = new Soy(darkRoast);
        System.out.println(darkRoast.getDescription() + " "+darkRoast.cost());
    }


扩展:

   java i/o中就大量使用装饰模式,比如FileInputStream可以被BufferedInputStream、LineNumberInputStream逐级装饰。有兴趣还可以去看看这些类的实现


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值