不看会后悔的装饰者模式

星巴兹是以扩张速度最快而闻名的咖啡连锁店。因为扩张速度过快,他们准备更新订单系统,以合乎他们的饮料供应要求。他们原先类设计是这样的。。

购买咖啡时,要求在其中加入各种调料,例如:蒸奶(steamed milk),豆浆(Soy)、摩卡(Mocha)或者其他。所以它们的订单系统必须考虑到调料部分。

他们尝试一次使用继承解决,如下图:

很明显如果每家一种调料都生成一个新类来继承父类Beverage,将会产生“类爆炸”,维护起来十分困难,如果调料价格上涨,新增调料,都会十分难以管理。

那么再尝试另外一种设计。

在父类Beverage中加上成员变量牛奶(milk)、豆浆(soy)、摩卡(mocha)、奶泡(whip.....)

这样的设计看起立已经比先前好多了。但是因为子类是直接继承父类的通用共享的成员变量和方法。所以扩展性,和代码会存在冗余。

例如:(1)增加新的饮料,比如茶,某些调料可能不适合,但在这个设计方式中,Tea子类仍将继承那些不合适的方法,例如hasWhip()(加奶泡)

             (2)调料的价钱改变需要改变现有代码

              (3)顾客想要双倍摩卡咖啡

认识装饰这模式

现在我们知道继承很好的解决我们的问题,上面设计中我们遇到了:类数量爆炸、设计死板、以及基类加入的功能并不适合所有的子类。

所以现在我们采用装饰者模式:我们以饮料为主体,然后运行时以调料来装饰饮料,比方说顾客想要摩卡和奶泡深焙咖啡,要做的是:

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

 

以装饰者构造饮料订单

(1)以DarkRoast对象开始

(2)顾客想要摩卡(Mocha),所以建立一个摩卡(Mocha)对象,并用它将DarkRoast对象包装起来。

(3)顾客也想要奶泡(Whip),所以要建立一个Whip装饰者,并用它将Mocha对象包起来。

(4)现在,是为顾客算钱的时候了。通过调用最外圈装饰者(Whip)的cost()就可以办到。Whip的cost()会委托它的装饰的对象计算出价钱,然后再加上奶泡的价钱。

目前通过上面的信息我们可以知道

  • 装饰者和被装饰者有相同的超类型。
  • 你可以用一个或者多个装饰者包装一个对象
  • 既然装饰者和被装饰对象有相同的类型,所以在任何需要原始对象(被包装的)场合,可以用装饰过的对象代替。
  • 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
  • 对象可以在任何时候被装饰,所以可以在运行时动态装饰想要装饰的对象。

定义装饰者模式

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

装饰饮料

写饮料的具体代码

Beverage相当于Component类

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

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

DarkRost相当于具体组件

public class DarkRost extends Beverage {

    public DarkRost() {
        description = "DarkRost";
    }

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

CondimentDecorator抽象装饰者

public abstract class CondimentDecorator extends Beverage{
    public abstract String getDescription();
}

具体装饰者Mocha

public class Mocha extends CondimentDecorator {

    Beverage beverage;

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

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

    @Override
    public double cost() {
        return 20+ beverage.cost();
    }
}

具体装饰者Whip

public class Whip extends CondimentDecorator {

    Beverage beverage;

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

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

    @Override
    public double cost() {
        return 30+beverage.cost();
    }
}

测试

public class Test {
    public static void main(String[] args) {
        Beverage beverage = new DarkRost();
        System.out.println(beverage.description+"   ,cost:"+beverage.cost());
         beverage = new Mocha(beverage);
        System.out.println(beverage.getDescription()+"   ,cost:"+beverage.cost());
         beverage = new Whip(beverage);
        System.out.println(beverage.getDescription()+"   ,cost:"+beverage.cost());
    }
}

输出结果:DarkRost   ,cost:100.0
DarkRost,Mocha   ,cost:120.0
DarkRost,Mocha,whip   ,cost:150.0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值