设计原则:类应该对扩展开放,对修改关闭
我们的目标是允许类容易扩展,在不修改代码的情况下,就可以搭配新的行为,如能实现这样的目标,这样的设计具有弹性,可以应对改变,可以接受新的功能来应对改变的需求
装饰者和被装饰者对象有相同的超类型
可以用一个或者多个装饰者包装一个对象
既然装饰者和被装饰者有相同的超类型,所以在任何需要原始对象的场合,可以用装饰过的对象代替它
装饰者模式:动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
装饰者类图
看个具体问题:
有一个咖啡店,他们有几种饮料,比如HouseBlend, DarkRoast.Decaf,Espresso
每种饮料里面可以加调料,可以加一种或者几种,也可以不加,调料有,SteamedMilk.Soy,Mocha等
计算一杯饮料的价格,包括饮料的价格和调料的价格
看一下类图
那么问题来了
如果需要添加新的调料,需要加上新的方法
如果价格修改了,需要修改父类的代码
有些饮料并不适合某些调料,仍然加入了判断
如果需要加入双倍的某种调料呢?
看新的类图
用代码来实现
package com.alvin.decorator;
public abstract class Beverage {
protected String description;
public abstract String getDescription();
public abstract float cost();
}
package com.alvin.decorator;
public class HouseBlend extends Beverage{
public float cost(){
return 1;
}
@Override
public String getDescription() {
return "HouseBlend";
}
}
package com.alvin.decorator;
public class Decaf extends Beverage {
@Override
public String getDescription() {
return "Decaf";
}
@Override
public float cost() {
return 3;
}
}
package com.alvin.decorator;
public class DarkRoast extends Beverage {
@Override
public String getDescription() {
return "DarkRoast";
}
@Override
public float cost() {
return 2;
}
}
package com.alvin.decorator.impl;
import com.alvin.decorator.Beverage;
public abstract class CondimentDecorator extends Beverage {
}
package com.alvin.decorator.impl;
import com.alvin.decorator.Beverage;
public class Milk extends CondimentDecorator {
private Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + "Milk";
}
@Override
public float cost() {
return beverage.cost() + 0.2f;
}
}
package com.alvin.decorator.impl;
import com.alvin.decorator.Beverage;
public class Mocha extends CondimentDecorator {
private Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + "Mocha";
}
@Override
public float cost() {
return beverage.cost() + 0.1f;
}
}
package com.alvin.decorator.impl;
import com.alvin.decorator.Beverage;
public class Soy extends CondimentDecorator {
private Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + "Soy";
}
@Override
public float cost() {
return beverage.cost() + 0.3F;
}
}
package com.alvin.decorator;
import com.alvin.decorator.impl.Milk;
import com.alvin.decorator.impl.Mocha;
import com.alvin.decorator.impl.Soy;
public class Run {
public static void main(String[] args) {
Beverage beverage = new DarkRoast();
System.out.println(beverage.getDescription() + beverage.cost());
Beverage beverage1 = new HouseBlend();
beverage1 = new Mocha(beverage1);
beverage1 = new Milk(beverage1);
beverage1 = new Soy(beverage1);
System.out.println(beverage1.getDescription() + beverage1.cost());
}
}
运行结果
DarkRoast2.0
HouseBlendMochaMilkSoy1.6000001
HouseBlendMochaMilkSoy1.6000001
在看一个JDK里面的类图来帮助理解输入输出流