Java设计模式3:装饰者模式

一.装饰者模式
1.介绍:
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
一层包一层

2.参与者:
◆抽象组件(Component)(抽象被装饰者):
所有组件和装饰者的超类,装饰者和被装饰对象要有相同的超类型
◆具体组件(ConcreteComponent)(具体被装饰者):
ConcreteComponent是我们将要动态地加上新行为 (装饰者) 的对象,它扩展自Component
◆抽象装饰者(Decorator):
维持一个指向抽象组件(Component)的引用,并作为具体装饰者共同实现的接口,以确保装饰者和组件拥有共同的超类。
◆具体装饰者(ConcreteDecorator):
.具体装饰者ConcreteDecorator有一个实例变量,可以记录所装饰的事物(装饰者包着的Component)
.装饰者可以加上新的方法。新行为是通过在旧行为前面或后面做一些计算来添加的

3.装饰者类图
在这里插入图片描述

4.特点
� 装饰者和被装饰对象有相同的超类型。
� 你可以用一个或多个装饰者包装一个组件(被装饰者)。
� 既然装饰者和被装饰对象有相同的超类型,所以在任何需要抽象组件的场合,
可以用装饰过的对象代替它。
� 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰
� 类应该对扩展开放,对修改关闭。

5.适用环境
(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)处理那些可以撤消的职责。
(3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的 子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

二.案例(咖啡店卖咖啡)
1.咖啡店的咖啡有上百种
2.每种咖啡都能添加不同的调味料
3.调味料也有几十种
4.如果用继承,定义一个父类饮料咖啡,几百个子类,显得很臃肿
5.而且咖啡和调味料之间不好维护
6.此时可以用装饰者模式

代码:
1.abstract class Beverage.java 所有饮料的超类 抽象饮料类(抽象组件Component)

package tiglle.patterns.decorator;
//所有饮料的超类 抽象饮料类(抽象组件Component)
public abstract class Beverage {
	//描述当前属于哪一种饮料
	String description = "Source Beverage";
	
	//获取描述的方法
	public String getDescription(){
		return description;
	}
	
	//必须由子类实现的抽象方法,计算当前饮料价格
	public abstract double cost();
	
}

2.abstract class Condiment.java 所有调味料的超类 抽象调味料(抽象装饰者Decorator)

package tiglle.patterns.decorator;
//所有调味料的超类 抽象调味料(抽象装饰者Decorator)
//继承抽象组件Beverage以保证 装饰者和组件超类型相同
public abstract class Condiment extends Beverage{
	
	//所有装饰者都要实现的重写了抽象组件的方法(根据业务需求),以便在获得描述时,加上调味料的信息
	@Override
	public abstract String getDescription();

}

3.class Espresso.java 浓缩咖啡(具体组件ConcreteComponent)

package tiglle.patterns.decorator;
//浓缩咖啡(具体组件ConcreteComponent)
public class Espresso extends Beverage{

	//实例化时初始化描述
	public Espresso() {
		description = "Espresso";
	}
	
	//计算返回浓缩咖啡的价格
	@Override
	public double cost() {
		return 1.99;
	}

}

4.class HouseBlend.java 混合咖啡(具体组件ConcreteComponent)

package tiglle.patterns.decorator;
//混合咖啡(具体组件ConcreteComponent)
public class HouseBlend extends Beverage{

	//实例化时初始化描述
	public HouseBlend() {
		description = "HouseBlend";
	}
	
	//计算返回浓缩咖啡的价格
	@Override
	public double cost() {
		return 0.99;
	}
}

5.class Mocha.java 摩卡 调味料,和组件拥有共同的超类(具体装饰者ConcreteDecorator)

package tiglle.patterns.decorator;
//摩卡 调味料,和组件拥有共同的超类(具体装饰者ConcreteDecorator)
public class Mocha extends Condiment{

	//被装饰的组件,使用多态定义
	private Beverage beverage;
	
	//实例化装饰者时 记录 要装饰的 组件
	public Mocha(Beverage beverage) {
		this.beverage = beverage;
	}

	//实现父类描述,在咖啡信息上加上调味料信息
	@Override
	public String getDescription() {
		return beverage.getDescription()+",Mocha";
	}

	//计算返回咖啡加上调味料的价格
	@Override
	public double cost() {
		//mocha的价格0.2
		return beverage.cost()+0.2;
	}
	
}

6.class Soy.java 调味料咖啡豆,和组件拥有共同的超类(具体装饰者ConcreteDecorator)

package tiglle.patterns.decorator;
//调味料咖啡豆,和组件拥有共同的超类(具体装饰者ConcreteDecorator)
public class Soy extends Condiment{

	//被装饰的组件,使用多态定义
	private Beverage beverage;
	
	//实例化装饰者时 记录 要装饰的 组件
	public Soy(Beverage beverage) {
		this.beverage = beverage;
	}

	//实现父类描述,在咖啡信息上加上调味料信息
	@Override
	public String getDescription() {
		return beverage.getDescription()+",Soy";
	}

	//计算返回咖啡加上调味料的价格
	@Override
	public double cost() {
		//Soy的价格0.3
		return beverage.cost()+0.3;
	}
}

7.class Whip.java 调味料奶泡,和组件拥有共同的超类(具体装饰者ConcreteDecorator)

package tiglle.patterns.decorator;
//调味料奶泡,和组件拥有共同的超类(具体装饰者ConcreteDecorator)
public class Whip extends Condiment{

	//被装饰的组件,使用多态定义
	private Beverage beverage;
	
	//实例化装饰者时 记录 要装饰的 组件
	public Whip(Beverage beverage) {
		this.beverage = beverage;
	}

	//实现父类描述,在咖啡信息上加上调味料信息
	@Override
	public String getDescription() {
		return beverage.getDescription()+",Whip";
	}

	//计算返回咖啡加上调味料的价格
	@Override
	public double cost() {
		//Whip的价格0.4
		return beverage.cost()+0.4;
	}
}

8.class MainExec.java Client测试main方法

package tiglle.patterns.decorator;
//Client测试main方法
public class MainExec {

	public static void main(String[] args) {
		/*********三个单身老外来到咖啡店***********************/
		//第一个老外:来一杯浓缩咖啡,什么调料都不要,多少钱?
		Beverage espressoA = new Espresso();//组件
		System.out.println("这是你的咖啡:"+espressoA.getDescription()+",价格:"+espressoA.cost());
		
		//第二个老外:来一杯杯浓缩咖啡,加 摩卡 咖啡店 奶泡  调味料,多少钱?
		Beverage espressoB = new Espresso();//组件(espressoB=Espresso)
		//加摩卡(用摩卡装饰组件)
		espressoB = new Mocha(espressoB);//此时,摩卡Mocha的beverage组件为Espresso(espressoB=Mocha)
		//加咖啡豆(用咖啡豆饰组件)
		espressoB = new Soy(espressoB);//此时,咖啡豆Soy的beverage组件为Mocha(espressoB=Soy)
		//加奶泡(用奶泡饰组件)
		espressoB = new Whip(espressoB);//此时,奶泡Whip的beverage组件为Soy(espressoB=Whip)
		/*
		 调用过程
		 1.执行Whip的getDescription和cost方法,因为Whip中的方法调用了当前组件beverage=Soy的getDescription和cost方法,所以先执行Soy
		 2.执行Soy的getDescription和cost方法,因为Soy中的方法调用了当前组件beverage=Mocha的getDescription和cost方法,所以先执行Mocha
		 3.执行Mocha的getDescription和cost方法,因为Mocha中的方法调用了当前组件beverage=Espresso的getDescription和cost方法,所以先执行Espresso
		 4.执行Espresso的getDescription和cost方法,并获得结果返回给Mocha,Mocha获得结果返回给Soy,Soy获得结果返回给Whip,Whip获得结果并展示
		 */
		System.out.println("这是你的咖啡:"+espressoB.getDescription()+",价格:"+espressoB.cost());
		
		//第三个老外:来一杯混合咖啡,我钱多,加 2份摩卡 1份咖啡店 1份奶泡  调味料,多少钱?
		Beverage espressoC = new HouseBlend();
		//加摩卡1(用摩卡1装饰组件)
		espressoC = new Mocha(espressoC);//此时,摩卡1Mocha1的beverage组件为Espresso(espressoC=Mocha1)
		//加摩卡2(用摩卡2装饰组件)
		espressoC = new Mocha(espressoC);//此时,摩卡2Mocha的beverage组件为Mocha1(espressoC=Mocha2)
		//加咖啡豆(用咖啡豆饰组件)
		espressoC = new Soy(espressoC);//此时,咖啡豆Soy的beverage组件为Mocha2(espressoC=Soy)
		//加奶泡(用奶泡饰组件)
		espressoC = new Whip(espressoC);//此时,奶泡Whip的beverage组件为Soy(espressoC=Whip)
		/*
		 调用过程
		 1.执行Whip的getDescription和cost方法,因为Whip中的方法调用了当前组件beverage=Soy的getDescription和cost方法,所以先执行Soy
		 2.执行Soy的getDescription和cost方法,因为Soy中的方法调用了当前组件beverage=Mocha2的getDescription和cost方法,所以先执行Mocha2
		 2.执行Mocha2的getDescription和cost方法,因为Mocha2中的方法调用了当前组件beverage=Mocha1的getDescription和cost方法,所以先执行Mocha1
		 3.执行Mocha1的getDescription和cost方法,因为Mocha1中的方法调用了当前组件beverage=Espresso的getDescription和cost方法,所以先执行Espresso
		 4.执行Espresso的getDescription和cost方法,并获得结果返回给Mocha1,Mocha1获得结果返回给Mocha2,Mocha2获得结果返回给Soy,Soy获得结果返回给Whip,Whip获得结果并展示
		 */
		System.out.println("土豪,这是你的咖啡:"+espressoC.getDescription()+",价格:"+espressoC.cost());
	}
}

运行结果:
这是你的咖啡:Espresso,价格:1.99
这是你的咖啡:Espresso,Mocha,Soy,Whip,价格:2.8899999999999997
土豪,这是你的咖啡:HouseBlend,Mocha,Mocha,Soy,Whip,价格:2.09
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值