一.概念
装饰者模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
二.意图
装饰者模式可以动态的给一些对象添加额外的功能,它比继承更具有弹性。
三.装饰者模式的结构图
说明:
● 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
● 具体构件(ConcreteComponent)角色:动态的加上新行为的对象,扩展自Component。
● 装饰(Decorator)角色:每个装饰者都“有一个”组件(Component)。
● 具体装饰(ConcreteDecorator)角色:继承抽象的装饰者,实现具体的自己的行为。
四.Demo举例
在《Head First 设计模式》中,饮料咖啡的例子中,当购买咖啡的时候,可以要求加入各种不同的调料摩卡(Mocha),豆浆(Soy)。咖啡店会根据不同的材料收取不同的费用,用多继承可是实现,但是继承太多,不同的咖啡配合不同的调料,会出现多种不同的结果。
如果用装饰者模式设计的话,步骤如下:
1.抽象组件:饮料的抽象类
public abstract class Beverage{
Stringdescription ="Unknown Beverage";
public StringgetDescription() {
return description;
}
public abstract double cost();
}
2.具体组件:不同的咖啡
//浓缩咖啡
public class Espressoextends Beverage{
public Espresso(){
description ="Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
//综合咖啡
public class HouseBlendextends Beverage{
public HouseBlend(){
description ="HouseBlend";
}
@Override
public double cost() {
return .89;
}
}
3.装饰者:调料的抽象类
public abstract class CondimentDecoratorextends Beverage{
public abstract StringgetDescription();
}
4.具体装饰者:不同的调料
//摩卡
public class Mochaextends CondimentDecorator{
Beveragebeverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public StringgetDescription() {
return beverage.getDescription() +", Mocha";
}
@Override
public double cost() {
return .20 +beverage.cost();
}
}
//豆浆
public class Beansextends CondimentDecorator{
Beveragebeverage;
public Beans(Beverage beverage) {
this.beverage = beverage;
}
@Override
public StringgetDescription() {
return beverage.getDescription() +", Beans";
}
@Override
public double cost() {
return .32 +beverage.cost();
}
}
5.应用
public void doSomeThing(){
//一杯浓缩咖啡,什么都不加
Beverage beverage =new Espresso();
System.out.println("desc : " + beverage.getDescription() +", cost : " + beverage.cost());
//摩卡浓缩咖啡
beverage =new Mocha(beverage);
System.out.println("desc : " + beverage.getDescription() +", cost : " + beverage.cost());
//摩卡,豆浆浓缩咖啡
beverage =new Beans(beverage);
System.out.println("desc : " + beverage.getDescription() +", cost : " + beverage.cost());
//豆浆综合咖啡
Beverage beverage1 =new HouseBlend();
beverage1 =new Beans(beverage1);
System.out.println("desc : " + beverage1.getDescription() +", cost : " + beverage1.cost());
}
运行结果是:
desc : Espresso, cost : 1.99
desc : Espresso, Mocha, cost : 2.19
desc : Espresso, Mocha, Beans, cost : 2.51
desc : HouseBlend, Beans, cost : 1.21
五.使用场景与优势
1.在不想增加很多子类的情况下扩展类。
2.动态增加功能,动态撤销。
3.装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
六.缺点
当装饰多层的时候,显得很复杂。