模拟需求
更新一个订单系统,以满足饮料供应要求。
原先的设计是这样的
每种饮料都需要实现cost抽象方法,来返回饮料的价钱。购买咖啡时也可以要求在其中加入各种调料,商家会根据不同的调料收取不同的费用。
如果这样设计:
这简直是“类爆炸”,基类中加入了新的功能并不适用于所有的子类,给维护造成了很大的困难,而且也不能应对需求的变化。继承是一种强耦合,在编译时就动态决定的,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
类应该对扩展开放,对修改关闭。
定义装饰者模式
装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
装饰饮料
不难发现,装饰者和被装饰者都继承了同一个抽象类。当我们将装饰者与组件组合时,就是在加入新的行为,所得到的行为不是继承于超类,而是由组合对象得来的。装饰类继承于抽象类,是为了有正确的类型,而不是继承它的行为。
代码实现
public abstract class Beverage{
String description = "Unknow Beverage';
public String getDescription(){
return description;
}
public abstract double cost();
}
//Condiment(调料)装饰抽象类
public abstract class CondimentDecorator extends Beverage{
//所有的调料必须重新实现getDescription方法
public abstract String getDescription();
}
//被装饰者
public class Espresso extends Beverage{
public Espresso(){
description = "Espresso";
}
public double cost(){
return 1.99;
}
}
//具体装饰类
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beveragge.getDescription() + ",Mocha";
}
pubic double cost(){
//要计算带Mocha饮料的价钱,首先把调用方法委托给被装饰对象计算,再加上Mocha的价钱
return 20 + beverage.cost;
}
}
//产生订单
public static void main (String[] args){
//制造一个饮料
Beverage beverage = new darkRoast();
//用Mocha装饰对象
beverage = new Mocha(beverage);
//用whip装饰对象
beverage = new Whip(beverage);
system.out.println(beverage.getDescription()+"$"+beverage.cost());
}
jdk中的装饰类:java/Io
BufferedInputStream和LineNumberInputStream都扩展自FilterInputStream,而FileInputStream是一个抽象的装饰类