定义
装饰者模式动态的将责任附加到对象,若要拓展功能,装饰者提供了比继承更有弹性的替代方案
按我的理解翻译:
当子类的行为增加时,继承只能修改代码,而组合动态可以在不修改代码的情况下动态进行扩展。
场景举例
现在有一家咖啡店要提供四种咖啡:HouseBlend、DarkRoast、Decaf和Espresso。这四种咖啡可以加任意调料组合成不同的饮料,例如牛奶摩卡浓缩咖啡(MilkMochaEspresso)
如果我们用继承实现这样的饮料框架,它将是:
父类通过设置调料的布尔值来控制cost
方法计算出所有调料的价格,然后子类cost
方法算出饮料价格+父类cost
计算的调料价格,获取真正的饮料价格。
我们很容易发现这样的实现不优雅,毛病很多。首先,每次拓展一种新饮料时,我们不得不修改父类的代码,而这样的修改可能影响到原有功能。
如何解决?我们先放出一个新的设计模式:
类应该对扩展开放,对修改关闭
也就是我们应该尽量让我们的代码具有拓展性,增加新需求时不需要更改老代码就可以拓展。
这里就需要用到装饰者模式的组合来替换基础了。
代码Demo
首先看一下装饰者模式的框架:
装饰者模式分为两个部分:组件(Component)和装饰者(Decorator),其中装饰者和组件的继承同一个类。
装饰者中组合了组件,这样就可以运用代理的思想对组件的方法进行修改和拓展,且不用修改原有代码。
我们以上面的咖啡店为例,看下装饰者模式的框架:
四种咖啡为组件,调料为装饰者,装饰者可以重复装饰装饰者,这样就获取了加了若干调料的饮料类。
好,现在放上Demo代码:
父类:
public abstract class Beverage {
public String name;
public String getName() {
return this.name;
}
public abstract double cost();
}
具体组件:
/**
* 浓缩咖啡
*/
public class Espresso extends Beverage{
public Espresso() {
this.name = "espresso";
}
@Override
public double cost() {
return 2.8;
}
}
/**
* 深焙咖啡
*/
public class DarkRoast extends Beverage{
public DarkRoast() {
this.name = "darkRoast";
}
@Override
public double cost() {
return 1.5;
}
}
调料装饰者:
/**
* 调料装饰父类
*/
public abstract class CondimentDecorator extends Beverage{
Beverage beverage;
@Override
public abstract String getName() ;
}
/**
* 牛奶调料
*/
public class Milk extends CondimentDecorator{
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getName() {
return beverage.getName() + ", Milk";
}
@Override
public double cost() {
return beverage.cost() + 1.0;
}
}
/**
* 摩卡调料
*/
public class Mocha extends CondimentDecorator{
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getName() {
return beverage.getName() + ", Mocha";
}
@Override
public double cost() {
return beverage.cost() + 0.8;
}
}
咖啡店测试:
/**
* 咖啡店
*/
public class CoffeeHouse {
public static void main(String[] args) {
//来一杯 深焙咖啡
Beverage beverage = new DarkRoast();
System.out.println(beverage.getName()+" $"+beverage.cost());
//来一杯 加牛奶的浓缩咖啡
Beverage beverage2 = new Espresso();
beverage2 = new Milk(beverage2);
System.out.println(beverage2.getName()+" $"+beverage2.cost());
//来一杯 加摩卡、牛奶的深焙咖啡
Beverage beverage3 = new DarkRoast();
beverage3 = new Mocha(beverage3);
beverage3 = new Milk(beverage3);
System.out.println(beverage3.getName()+" $"+beverage3.cost());
}
}/**output:
darkRoast $1.5
espresso, Milk $3.8
darkRoast, Mocha, Milk $3.3
*/
JAVA中的装饰者模式
Java源码中许多地方运用到了装饰者模式,例如IO相关类: