需求
咖啡店,客户可能会叫一种饮料,并且指定某些调料加入进去,比如深焙咖啡,用摩卡,奶泡,牛奶作为调料,计算出总价
饮料类,被装饰者
/**
* 饮料父类
*/
public abstract class Beverage
{
/**
* 描述饮料的字段
*/
protected String description = "Unknown Berverage";
public String getDescription()
{
return description;
}
/**
* 计算价钱的方法,必须在子类中实现
*/
public abstract double cost();
}
/**
* 暗烤咖啡
*/
public class DarkRoast extends Beverage
{
public DarkRoast()
{
description = "暗烤咖啡 DarkRoast"; // 描述此饮料
}
/**
* 返回此饮料的价钱
*/
@Override
public double cost()
{
return .99;
}
}
调料类,装饰者
/**
* 调料类,也就是装饰者
*
* 为了让 装饰者 能够替代 被装饰者 ,因此 装饰者 继承 被装饰者
*/
public abstract class Condiment extends Beverage
{
/**
* 所有的装饰者类,都必须重新实现此方法,因为必须有不同的名称
*/
@Override
public abstract String getDescription();
}
/**
* 摩卡调料
*/
public class Mocha extends Condiment
{
private Beverage beverage; // 用来记住 被装饰者 ,也就是此调料要加在哪个饮料上
/**
* 想办法把被装饰者记录在变量中
*/
public Mocha(Beverage beverage)
{
this.beverage = beverage;
}
/**
* 把被装饰者和装饰者的名称组合起来,比如:混合咖啡,摩卡
*/
@Override
public String getDescription()
{
return beverage.getDescription() + ", 摩卡调料 Mocha";
}
/**
* Mocha自身的价钱+饮料的价钱
*/
@Override
public double cost()
{
return 0.20 + beverage.cost();
}
}
/**
* 豆奶调料
*/
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()
{
return .15 + beverage.cost();
}
}
测试
// 点一杯饮料
Beverage beverage2 = new DarkRoast();
// 用调料去装饰饮料
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
// 算出总价钱
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
疑问
- 以上全用了继承,这里是利用继承达到类型匹配的目的,并不是获得行为。方便更有弹性的混合匹配
- 每当需要新的调料,甚至是新的饮料,都可以新增并方便的加入
- 并非一定要用接口,如果抽象类用的好好的,并且已经满足需求,就不用再去修改他
- 会导致有很多的小类
Java 中应用到装饰者模式的地方
Java I/O
设计原则 5
类应该对扩展开放,对修改关闭,在不修改现有代码的情况下,就搭配新的行为
装饰者模式定义:
动态的将责任附加到对象上,对于扩展的话,比继承更有弹性。