我的武林秘籍设计模式之装饰者模式

喝咖啡是大多数上班族的习惯,jack作为他们公司的骨干,自然少不了喝咖啡。

在他们公司楼下,有一家叫星巴拉咖啡店,该公司营业有方正以每天两家分店的速度向外扩张。

星巴拉咖啡打算更新一下他们的订单系统,以合乎他们的饮料供应。

一个周六的下午,jack来到了星巴拉咖啡,在柜台前点了一杯拿铁,并要求配料中加两份牛奶,但是它的订单系统并不能支持,只能给他加一份。

好家伙这可给jack急的,店员立马找来了门店经理。

经理告诉jack,他们的订单系统目前比较落后,目前正筹划更新系统呢。

jack看了他们原先的系统类图是这样的

再接着,他们的各种咖啡中还能在其中加入各种调料,例如:牛奶(milk),豆浆(soy),摩卡(mocha)等。会根据所添加的不同调料而收取相应费用。

这是第一个尝试

看了这样的类图简直是类爆炸,每一个咖啡和每一个配料组合一起为一个类,要是配料多起来就要为每一种咖啡都要加一个该配料的类。简直是一个恶梦,难怪无法满足jack加两份牛奶的需求,而且如果牛奶价格上扬的话,他就要修改所有加了牛奶的咖啡类。

于是jack脑子立马又浮现了一个设计,让Beverage咖啡类里包含配料的属性,和他的方法,见类图

但是作为外行人的门店经理,仿佛通灵一般,看出了该系统存在的缺陷。

经理说:“jack啊,咱这个系统要是改了配料的价格的话,就要修改所有的咖啡类了,要是以后还有其他的茶类的话,这些配料像牛奶,摩卡都不能使用的。要是有的顾客挑剔一点的话,要加两份牛奶的话,那也没办法实现啊”

jack说:“老铁,没毛病!”

于是jack又开始头脑风暴了。

此刻,jack面临了一种重要的设计原则,那就是开闭原则

开闭原则:类应该对扩展开放,对修改关闭。我们的目标是允许类容易扩展,在不修改现有代码的情况下,可以添加新的行为。

于是jack想到了装饰者模式,装饰者模式是要先定义一个组件,那就是抽象组建,那就是Beverage,然后是具体的咖啡类都去继承beverage,再定义一个配料类CondimentDecorator,也去继承Beverage,然后具体的配料再去继承CondimentDecorator,这样所有类的父类都是Beverage。配料类中有一个Beverage类属性维护(这是装饰者模式的精华所在,把被装饰的咖啡注入这个属性,能得到原来被装饰时的价格)。

现在我们实现代码

package coffer;

/**
 * 这是抽象类,是咖啡和调料的父类
 * Created by huangx on 2018/11/15.
 */
public abstract class Beverage {
    public abstract String getDescription();
    public abstract int cost();
}



package coffer;


package coffer;

/**
 * 这是调料装饰者,继承与Beverage
 * Created by huangx on 2018/11/15.
 */
public abstract class CondimentDecorator extends Beverage {

    Beverage beverage;

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

    public abstract String getDescription();

    public abstract int cost();
}


package coffer;

/**
 * 这是具体的组件超优深焙咖啡
 * Created by huangx on 2018/11/15.
 */
public class DarkRoast extends Beverage {


    public String getDescription() {
        return "i am darkRoast ";
    }

    public int cost() {
        return 15;
    }
}
package coffer;

/**
 * 这是具体组件 中优深焙咖啡,我们就实现这两种咖啡,其他类型的拿铁(latter),脱咖啡因咖啡(decaf)也是一样,就不写了
 * Created by huangx on 2018/11/15.
 */
public class HouseBlend extends Beverage {

    public String getDescription() {
        return "i am houseBlend  ";
    }

    public int cost() {
        return 12;
    }
}
package coffer;

/**
 * 具体的装饰者,即调料
 * Created by huangx on 2018/11/15.
 */
public class Milk extends CondimentDecorator {

    public Milk(Beverage beverage) {
        super(beverage);
    }

    public String getDescription() {
        return beverage.getDescription() + "add milk ";
    }

    public int cost() {
        return 5 + beverage.cost();
    }
}
package coffer;

/**
 * 具体的装饰者,即调料,其他的Soy,whip调料也不写了
 * Created by huangx on 2018/11/15.
 */
public class Mocha extends CondimentDecorator {

    public Mocha(Beverage beverage) {
        super(beverage);
    }

    public String getDescription() {
        return beverage.getDescription() +"add mocha ";
    }

    public int cost() {
        return 7 + beverage.cost();
    }
}
package coffer;

/**
 * 测试类
 * Created by huangx on 2018/11/15.
 */
public class TestApplication {
    public static void main(String[] args) {
        Beverage beverage = new Milk(new Mocha(new Mocha(new DarkRoast())));
        System.out.println(beverage.getDescription() + "--------- 需要支付" + beverage.cost());
    }
}

运行结果:

本例中的装饰者是配料,被装饰的是咖啡。咖啡作为配料的属性进行注入,并由此得到价格,当然可以再用这个装饰后的咖啡,再被装饰一下,又得出了一个新的价格。

bingo,jack终于可以大肆的加牛奶了。老板为了答谢jack的设计,决定每次jack来店点单,都给他的咖啡免费加五份牛奶。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值