设计模式——装饰模式(Decorator)

概念

装饰模式又名包装(Wrapper)模式。装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

针对的问题

动态的给一个对象添加一些额外的职责,就增加功能来说,Decorator模式相比生成子类更为灵活。不改变接口的前提下,增强所考虑的类的性能。

何时使用:

  • 需要扩展一个类的功能,或给一个类增加附加责任。
  • 需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
  • 需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承变得不现实。

总的来说,就是给原有的类增加新的功能,假如有5种咖啡,4种配料(糖和牛奶,蜂蜜,巧克力),如果要生成子类的话就会有5×4=20个子类,这样就太多了,通过装饰器模式就只用写5+4+装饰器类这么多就好,装饰器的意思就是给原来的咖啡加入装饰(这里的装饰指的就是配料)。

角色构成

抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。

具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。

装饰角色(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口,也就是要有原来抽象构件中的全部方法。

具体装饰角色(ConcreteDecorator):负责给构件对象“贴上”附加的责任。

1

举例

还是刚才的咖啡的例子,

这里的抽象构件(Component)角色就是饮料,饮料接口对各种咖啡进行限制。

具体构件(ConcreteComponent)角色 就是各种咖啡。

现在要往咖啡中加入配料了

装饰器(Decorator) 加了一种配料的咖啡,但是具体加了什么配料不知道,由具体的子类决定。

具体装饰角色 就是各种咖啡以及加了配料的类,

1
2
3
4
5
6
7
8
9
/** 
* 饮料接口
*/
public interface Beverage {
//返回商品描述
public String getDescription();
//返回价格
public double getPrice();
}
1
2
3
4
5
6
7
8
9
10
11
public class CoffeeBean1 implements Beverage {  
private String description = "选了第一种咖啡豆";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 50;
}
}
1
2
3
4
5
6
7
8
9
10
11
public class CoffeeBean2 implements Beverage {  
private String description = "第二种咖啡豆!";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 100;
}
}
1
2
3
4
5
6
7
8
9
10
11
public class Decorator implements Beverage {  
private String description = "我只是装饰器,不知道具体的描述";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 0; //价格由子类来决定
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Milk extends Decorator{  
private String description = "加了牛奶!";
private Beverage beverage = null;
// 注意milk的构造方法。
public Milk(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+20; //20表示牛奶的价格
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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表示摩卡的价格
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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表示豆浆的价格
}
}
1
2
3
4
5
6
7
8
9
10
//测试
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());
}
}