装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰(Decorator)模式的使用场景:
- 需要扩展一个类的功能,或给一个类增加附加责任。
- 需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
- 需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承变得 不现实。
装饰(Decorator)模式的主要优点有:
- 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
- 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。
其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。
装饰(Decorator)模式的结构
装饰模式主要包含以下角色:
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
- 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
装饰模式的结构图如下所示
装饰模式的结构图
举例说明:
咖啡是一种饮料,咖啡的本质是咖啡豆+水磨出来的。咖啡店现在要卖各种口味的咖啡,如果不使用装饰模式,那么在销售系统中,各种不一样的咖啡都要产生一个类,如果有4中咖啡豆,5种口味,那么将要产生至少20个类(不包括混合口味),非常麻烦。使用了装饰模式,只需要11个类即可生产任意口味咖啡(包括混合口味)。
类图
Beverage饮料接口
/**
* 饮料接口
* @author Administrator
*
*/
public interface Beverage {
//返回商品描述
public String getDescription();
//返回价格
public double getPrice();
}
CoffeeBean1——具体被装饰的对象类1
public class CoffeeBean1 implements Beverage {
private String description = "选了第一种咖啡豆";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 50;
}
}
CoffeeBean2——具体被装饰的对象类2
public class CoffeeBean2 implements Beverage {
private String description = "第二种咖啡豆!";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 100;
}
}
Decorator——装饰类
public class Decorator implements Beverage {
private String description = "我只是装饰器,不知道具体的描述";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 0; //价格由子类来决定
}
}
Milk——具体装饰类,给咖啡加入牛奶
public class Milk extends Decorator{
private String description = "加了牛奶!";
private Beverage beverage = null;
public Milk(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+20; //20表示牛奶的价格
}
}
Mocha——给咖啡加入摩卡
public class Mocha extends Decorator {
private String description = "加了摩卡!";
private Beverage beverage = null;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+49; //30表示摩卡的价格
}
}
Soy——给咖啡加入豆浆
public class Soy extends Decorator {
private String description = "加了豆浆!";
private Beverage beverage = null;
public Soy(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+30; //30表示豆浆的价格
}
}
测试类:
public class Test {
public static void main(String[] args) {
Beverage beverage = new CoffeeBean1(); //选择了第一种咖啡豆磨制的咖啡
beverage = new Mocha(beverage); //为咖啡加了摩卡
beverage = new Milk(beverage);
System.out.println(beverage.getDescription()+"\n加了摩卡和牛奶的咖啡价格:"+beverage.getPrice());
}
}