装饰器模式是我本人觉得非常巧妙的一种设计模式,值得细细品味。
1 介绍
允许向一个现有的对象添加新的功能,同时又不改变其结构。
2 例子
假设一个饮品店卖饮料,各个饮料口味不同(多糖、少糖、加奶、不加奶)价格也不一样。
2.1 饮料抽象类
//饮料的抽象类
interface Drink {
int cost();
String info();
}
2.2 咖啡实体
//咖啡实现饮料
class Coffee implements Drink{
private int price = 20;//基础咖啡价格需要20
private String name = "咖啡";//基础咖啡的名字
@Override
public int cost() {
return this.price;
}
@Override
public String info() {
return this.name;
}
}
2.3 加佐料的饮料抽象类(核心)
//抽象装饰器类(就是那些加佐料的抽象类)
abstract class Decorate implements Drink {
private Drink drink;//聚合一个饮料的接口
//构造函数
public Decorate(Drink drink) {
this.drink = drink;
}
//返回具体饮料具体的基础费用
@Override
public int cost() {
return drink.cost();
}
@Override
public String info() {
return drink.info();
}
}
这是装饰器的核心,这里面有两个维度,第一个维度是实现了饮料接口,表示这还是一杯饮料,第二个维度是聚合了一个饮料接口,表示该饮料还含有一款基础饮料。
2.4 实现加佐料的饮料
//加奶饮料
class AddMilkDrink extends Decorate {
public AddMilkDrink(Drink drink) {
super(drink);
}
@Override
public int cost() {
return super.cost() + 10;
}
@Override
public String info() {
return super.info() + "加牛奶";
}
}
//加糖饮料
class AddSugarDrink extends Decorate {
public AddSugarDrink(Drink drink) {
super(drink);
}
@Override
public int cost() {
return super.cost() + 5;
}
@Override
public String info() {
return super.info() + "加糖";
}
}
2.5 测试主类
public class Main {
public static void main(String[] args) {
//基础咖啡
Drink coffee=new Coffee();
//加糖
Drink addSugarDrink=new AddSugarDrink(coffee);
//加奶
Drink addMilkDrink=new AddMilkDrink(addSugarDrink);
System.out.println(addMilkDrink.info()+":"+addMilkDrink.cost());
}
}
运行结果:
咖啡加糖加牛奶:35
3 例子升华
首先,饮料这个接口把整个项目定了调,这里面所有的类都是饮料。基础款:类似于咖啡、果汁、果茶等。加料款,这是核心,加料的饮料还是饮料,所以要实现饮料接口,关键就在于聚合的那个饮料,可以是一个基础款也可以是一个加料款,非常巧妙。
4 总结
4.1 核心角色
- 主体抽象接口:定调;
- 主体:实现主体抽象;
- 抽象装饰类(核心):包含了主体抽象接口引用(聚合),同时实现了主体抽象接口。相当于即是主体,又含有基础主体的引用(方便累加)。
- 装饰类:抽象装饰的实现。
4.2 核心代码结构
抽象装饰类:聚合主体抽象又实现主体抽象。