一.装饰者模式
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