咖啡店的需求
你的项目组最近接到一个项目,要为一家咖啡店升级订单系统,原有设计如下
代码如下:
/**
* 饮料的基类,所有饮料继承该接口
*/
public interface Beverage {
String getDescription();
double cost();
}
public class Espresso implements Beverage {
@Override
public String getDescription() {
return "美式咖啡";
}
@Override
public double cost() {
return 12;
}
}
现在咖啡店想要给咖啡加调料,根据调料不同,显示的描述不同,价格也不同,应该如何设计系统呢?
新的设计
根据需求,其实就是在原有类上加强功能,并且功能是可以灵活组合的,比如可以加奶,加豆浆,或者加双倍的奶,这就可以使用装饰者模式
装饰者模式的特点是:向一个现有的对象添加新的功能,同时又不改变其结构。属于对象结构型模式。
创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能
CondimentDecorator是加调料的装饰类,之所以要继承Beverage,是为了继承其类型,这样使用饮料的地方就能用这个装饰者来代替
下面看下装饰类的实现
/**
* 调味品装饰基类
*/
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
/**
* 每个装饰类需要传入真正的饮料
*/
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
}
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ",加奶";
}
@Override
public double cost() {
// 加奶多两元
return beverage.cost() + 2;
}
}
public class Soy extends CondimentDecorator {
public Soy(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ",加豆浆";
}
@Override
public double cost() {
// 豆浆加3元
return beverage.cost() + 3;
}
}
可以看到装饰类都需要传入真正的饮料,也就是被装饰的对象,然后在其基础上做功能的加强
测试一下代码,发现可正确计算出价格
public class MainTest {
public static void main(String[] args) {
// 要一杯浓缩咖啡,加奶加豆浆
Beverage coffe = new Espresso();
coffe = new Milk(coffe);
coffe = new Soy(coffe);
System.out.println(coffe.getDescription());
System.out.println(coffe.cost());
// 要一杯焦炒咖啡,加双倍奶加豆浆
Beverage coffe1 = new DarkRoast();
coffe1 = new Milk(coffe1);
coffe1 = new Milk(coffe1);
coffe1 = new Soy(coffe1);
System.out.println(coffe1.getDescription());
System.out.println(coffe1.cost());
}
}
输出:
美式咖啡,加奶,加豆浆
17.0
焦炒咖啡,加奶,加奶,加豆浆
22.0
扩展
看类图可以看到装饰者模式和代理模式挺像的,装饰器和代理之间的区别很细微,可以认为装饰器是代理的一个子集。静态代理就是装饰器的方式