装饰者模式

基本定义

给对象赋予超能力

动态的将责任附加到对象上。想要提供功能,装饰者提供有别于继承的另一种选择。在不修改底层代码的情况下,给对象赋予新的职责

入门

孙悟空有72般变化,他的每一种变化带来一种附加的本领。他变成鱼儿时,就可以到水里游泳;他变成雀儿时,就可以到天上飞。而在二郎神的眼里,他永远是那只猢狲
在这里插入图片描述

  • 在装饰模式中各个角色有
    1. 抽象构建(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
    2. 具体构件(Concrete Component)角色:定义一个附加责任的类。
    3. 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
    4. 具体装饰角色(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。

案例

问题 星巴兹(starbuzz)是以速度扩张最快而闻名的咖啡连锁店,如果你在街角看到他的店,在对面的街上肯定还会看到另一家。因为扩张实在太快,他们准备更新订单系统,以合乎他们的饮料供应要求。下面使他们原先的设计

https://mp.youkuaiyun.com/mdeditor/88303336#
不合理原因

  1. 调整价格会使我们更改现有的代码
  2. 一旦出现新饮料,我们就需要加新的方法,并改变超类中的cost()方法
  3. 开发新饮料,对这些饮料而言可能并不合适,例如(冰茶)子类仍将继承hashWhip()(加奶泡)
  4. 外衣顾客想要双倍摩卡咖啡的话,将无法实现

以装饰者构造饮料订单

  1. 以DarkRoast对象开始
    在这里插入图片描述
  2. 顾客想要摩卡(Mocha),所以建立一个Mocha对象,并用它将DarkRoast对象(wrap)起来
    在这里插入图片描述
  3. 顾客也想要奶泡(Whip),所以需要建立一个Whip装饰者,并用它将Mocha对象包裹起来。别忘了,DarkRoast继承自Beverage,且有一个coast()方法,用来计算饮料价格
    在这里插入图片描述
  4. 现在为顾客算钱。通过调用最外圈的装饰者(Whip)的cost()就可以了办得到。Whip的cost()会先委托它装饰的对象(也就是Mocha)计算出价格,然后在加上奶泡的价格

上述所讲总结

将饮料当做大圣本身,调料当做大圣化生。每一次加入调料相遇于饮料增加一种功能。如大圣化为鸟被赋予飞的能力,化为鱼拥有潜水的本领…但是不管怎么变,猴子在二郎神的眼里还是那个猢狲。饮料加了配料还是饮料

  • 装饰者和被装饰者对象拥有相同的超类型
  • 可以用一个或者多个装饰者包装一个对象
  • 根据里式替换原则,任何原始对象都可以被装饰过的对象代替他
  • 装饰者可以在所委托被装饰者的行为之前或者与/或之后,加上自己的行为,已达到特定的目的
  • 虽然Decorator不一定是抽象类,但由于他的功能是抽象一个抽象角色,因此也常常称他为抽象装饰

基于装饰者模式设计

在这里插入图片描述
Beverage(饮料)类

// 该类为抽象类
public abstract class Beverage {
	String description = "Unknown Beverage";
	public String getDescription() {
		return description;
	}
	public abstract double cost();
}

实现Condiment(调料)抽象类

public abstract class CondimentDecorator extends Beverage {
	// 所有的调料都必须重新实现getDescription()方法,这个在具体的Condiment(调料)类中讲解
	public abstract String getDescription();
}

具体饮料

  1. 浓缩咖啡Espresso
    public class Espresso extends Beverage {
    	public Espresso() {
    		//该变量继承自Beverage
    		description = "Espresso";
    	}
    	public double cost() {
    		//现在不管调料的价格,直接返回Espresso的价格$1.99
    		return 1.99;
    	}
    }
    
  2. 综合咖啡HouseBlend
    public class HouseBlend extends Beverage{
    	public Espresso() {
    		//该变量继承自Beverage
    		description = "HouseBlend";
    	}
    	public double cost() {
    		//现在不管调料的价格,直接返回Espresso的价格$1.99
    		return 0.89;
    	}
    }
    

具体配料 Mocha

public class Mocha extends CondimentDecorator {
	Beverage beverage;
	//把饮料当做构造器参数,可以让被装饰者(饮料)被记录到实例变量中
	public Mocha(Beverage beverage) {
		this.beverage = beverage;
	}
	public String getDescription() {
		//这里解释上面抽象配料描述设置为抽象的原因
		//我们希望打印的不仅是饮料,而是可以完整的将配料同时写出来
		return beverage.getDescription() + ", Mocha";
	}
	public double cost() {
		//计算带Mocha饮料的价格,调用委托被装饰的对象计算价格然后加上Mocha价格,得到最后的结果
		return 0.20+beverage.cost();
	}
}

测试类 starBuzzCoffee

public class starBuzzCoffee{
	public static void main(String[] args) {
		//定制一杯不要饮料的Espresso
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription()+"$"+beverage.cost());
		
		//定制一份加了双摩卡黑暗考的饮料
		Beverage beverage2 = new DarkRoast();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription()+"$"+beverage2.cost());
	}
}

应用情况

  • 需要扩展一个类,或给一个类附加责任
  • 需要给一个对象动态增加功能,同时可以撤销
  • 需要增加一些基本功能的排列组合而产生大量的功能,从而继承关系变得不现实
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值