装饰器模式是一种结构型设计模式,它允许通过将对象放入包装器中来为原始对象增强功能。 这些包装器(称为装饰器),能够在不改变原始对象代码的情况下,动态地为其添加新的行为和属性。
装饰器模式由 4 部分组成:
-
抽象构建
-
具体构建
-
装饰器
-
具体装饰角色
案例:在生活中我们需要提供一个咖啡点单系统。咖啡提供了描述信息个获取获取价格,如果说 我们提供了加牛奶的服务,在计算价格时就得床架很多相应的牛奶咖啡类了。也会出现类爆炸
这时就可以使用装饰着模式解决这个问题。
我们提供一个咖啡装饰器,使用装饰器模式做明显的特征就是 装饰器需要实现被装饰的产品,同时也需要将产品组合到装饰器中。
代码实现:
1、创建抽象构建【咖啡,Coffee】,提供获取名称和价格两个抽象方法
/**
* 抽象组件
**/
public interface Coffee {
String getName();
Double getPrice();
}
2、创建具体组件,咖啡的一种具体类型【卡布奇诺,KabuqinuoCoffee】,具体组件需要实现抽象组件
public class KabuqinuoCoffee implements Coffee {
@Override
public String getName() {
return "卡布奇诺";
}
@Override
public Double getPrice() {
return 12.60;
}
}
3、创建抽象装饰器【CoffeeDecorator】,同样需要实现抽象构建,这样在后面具体装饰器才有获取咖啡的名称和价格的方法。同时需要将抽象组件作为成员变量聚合到抽象装饰器中,目的是在某一个具体的咖啡组件上做增强,所以需要提前将具体的咖啡组件传递给装饰器。
/**
* 装饰器
* 需要实现 Coffee
**/
public class CoffeeDecorator implements Coffee{
/**
* 原始咖啡,没有增强的咖啡
**/
private final Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
/**
* 原始咖啡的姓名
**/
@Override
public String getName() {
return coffee.getName();
}
/**
* 原始咖啡的价格
**/
@Override
public Double getPrice() {
return coffee.getPrice();
}
}
装饰器的作用是做具体构建进行进一步的升级,所以说我们需要获取具体的产品,并且返回产品封装之后的信息所以说,就需要将抽象构建组合【聚合也合理】到装饰器,同时装饰器也需要实现或者继承抽象构建,这样子在后续的具体装饰角色在创建的时候就可以返回在抽象构建的基础上进一步升级了。
4、声明具体装饰器【牛奶咖啡】,在咖啡的基础上可以加牛奶
/**
* 牛奶咖啡
**/
public class MikeCoffee extends CoffeeDecorator{
/**
* 在创建构造器时需要将原始咖啡传递给装饰器
**/
public MikeCoffee(Coffee coffee) {
super(coffee);
}
/**
* 返回增强后的名称
**/
@Override
public String getName() {
return super.getName() + "加奶牛";
}
/**
* 返回增强后的价格
**/
@Override
public Double getPrice() {
return super.getPrice() + 3.50;
}
}
5、测试
public static void main(String[] args) {
//初始化一杯卡布奇诺咖啡
KabuqinuoCoffee kabuqinuoCoffee = new KabuqinuoCoffee();
String kabuqinuoCoffeeName = kabuqinuoCoffee.getName();
Double kabuqinuoCoffeePrice = kabuqinuoCoffee.getPrice();
System.out.println("kabuqinuoCoffeeName = " + kabuqinuoCoffeeName);
System.out.println("kabuqinuoCoffeePrice = " + kabuqinuoCoffeePrice);
System.out.println("============================");
//初始化一杯牛奶咖啡,在卡布奇诺的基础上加牛奶
MikeCoffee mikeCoffee = new MikeCoffee(kabuqinuoCoffee);
String mikeCoffeeName = mikeCoffee.getName();
Double mikeCoffeePrice = mikeCoffee.getPrice();
System.out.println("mikeCoffeeName = " + mikeCoffeeName);
System.out.println("mikeCoffeePrice = " + mikeCoffeePrice);
}
//测试结果
kabuqinuoCoffeeName = 卡布奇诺
kabuqinuoCoffeePrice = 12.6
============================
mikeCoffeeName = 卡布奇诺加奶牛
mikeCoffeePrice = 16.1
Process finished with exit code 0