设计模式之装饰者模式

装饰者模式

星巴克咖啡是以扩张速度最快而闻名的咖啡连锁店,他们的订单系统起初是这样设计的

子类实现cost方法后即可返回相应咖啡的价钱

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kJEwHeGC-1623291547891)(C:\Users\Administrator.DESKTOP-GE4QENT\AppData\Roaming\Typora\typora-user-images\image-20210610091333608.png)]

但是很快,星巴克又引入了许多调料,例如蒸奶(Steamed Milk)、豆浆(Soy)、摩卡(Mocha)或奶泡等,要根据加入调料的不同收取不同的费用,所以系统中必须考虑到调料部分

我们拿首选综合咖啡举例,会出现类爆炸的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hHAZCneu-1623291547894)(C:\Users\Administrator.DESKTOP-GE4QENT\AppData\Roaming\Typora\typora-user-images\image-20210610091944422.png)]

很明显,这种设计方法是非常难以维护的,不仅仅在于类爆炸的问题,当牛奶价格上涨时,需要更改极其多的类的返回价格,当新增一种调料时,又会产生极其多的类,这是维护上的噩梦,那么我们应该怎么解决这个问题呢,我们想到了继承

从基类Beverage下手,加上各种调料的布尔值,在基类中算出我们要加入哪些调料的总价格,加上子类咖啡的价格即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tAbLHzsO-1623291547895)(C:\Users\Administrator.DESKTOP-GE4QENT\AppData\Roaming\Typora\typora-user-images\image-20210610093147669.png)]

这样便解决了类爆炸的问题,同时也较利于维护

有一天,星巴克上架了矿泉水,顾客想要一瓶水,同时加一份奶,再加一份豆浆,同时再加双倍摩卡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-acFDVeUA-1623291547897)(C:\Users\Administrator.DESKTOP-GE4QENT\AppData\Roaming\Typora\typora-user-images\image-20210610093959974.png)]

众所周知,水里面怎么能加奶和豆浆呢,这就产生了功能不适用的问题

双倍摩卡系统也不会给予支持

在设计模式中,类应该是对扩展开放,对修改关闭的,每当我们要上架一种新调料时,上述设计方法都会使我们去更改基类中的代码

那么怎么设计才能使系统没有类爆炸、设计死板的问题,又能解决功能不适用的麻烦,满足设计原则呢?

装饰者模式带给了我们答案

我们要以饮料为主体,然后在运行时以调料来“装饰”饮料

比方说,如果顾客想要摩卡和奶泡深烘培的咖啡,那么我们要做的是:

  • 拿一个深烘培咖啡对象
  • 以摩卡对象装饰它
  • 以奶泡对象装饰它
  • 调用cost方法,并将调料的价钱加上去

让我们看看系统是什么样的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0Rgmhas-1623291547898)(C:\Users\Administrator.DESKTOP-GE4QENT\AppData\Roaming\Typora\typora-user-images\image-20210610100224492.png)]

调料的具体实现举例:

public class Milk extends CondimentDecorator{
    Beverage beverage;
    public Milk(Beverage beverage){
        this.beverage = beverage;
    }
    public String getDescription(){
        return beverage.getDescription() + ", Milk";
    }
    public double cost(){
        return beverage.cost() + 20;
    }
}

订单过程:

Beverage beverage = new HouseBlend(); //创建一个首选综合咖啡
beverage = new Mocha(beverage);  //引用指向一个摩卡对象,摩卡对象中包含首选综合咖啡
beverage = new Mocha(beverage); //引用指向一个摩卡对象,摩卡对象中包含一个内摩卡对象,包含的内摩卡对象中包含首选综合咖啡
beverage = new Milk(beverage); //引用指向一个牛奶对象,牛奶对象中包含上述外摩卡对象
System.out.println(beverage.getDescription() + " " + beverage.cost());

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值