装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

类图示例

装饰模式.png

举个例子

假设我们有一个简单的咖啡售卖系统。咖啡有不同的种类(如拿铁、美式咖啡),并且可以添加各种配料(如牛奶、糖、奶油)来改变咖啡的口味和价格。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//抽象咖啡类
abstract class Coffee{
public abstract double cost();
public abstract String name();
}

//拿铁
class Latte extends Coffee{
public double cost(){
return 2.5;
}
public String name(){
return "Latte";
}
}

//咖啡装饰器抽象类
abstract class CoffeeDecorator extends Coffee{
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee){
this.coffee = coffee;
}
}

//牛奶装饰器类
class MilkDecorator extends CoffeeDecorator{
public MilkDecorator(Coffee coffee){
super(coffee);
}
public double cost(){
return coffee.cost()+0.5;
}
public String name(){
return coffee.name()+", Milk";
}
}

//糖装饰器
class SugarDecorator extends CoffeeDecorator{
public SugarDecorator(Coffee coffee){
super(coffee);
}
public double cost(){
return coffee.cost()+0.5;
}
public String name(){
return coffee.name()+", Sugar";
}
}

public class Decoration {
public static void main(String[] args) {
Coffee coffee = new Latte();
System.out.println(coffee.name());
coffee=new MilkDecorator(coffee);
System.out.println(coffee.name());
coffee=new SugarDecorator(coffee);
System.out.println(coffee.name());
}
}

装饰模式包含如下角色

  1. 抽象组件(Component):定义了原始对象和装饰器对象的公共接口或抽象类,可以是具体组件类的父类或接口。
  2. 具体组件(Concrete Component):是被装饰的原始对象,它定义了需要添加新功能的对象。
  3. 抽象装饰器(Decorator):继承自抽象组件,它包含了一个抽象组件对象,并定义了与抽象组件相同的接口,同时可以通过组合方式持有其他装饰器对象。
  4. 具体装饰器(Concrete Decorator):实现了抽象装饰器的接口,负责向抽象组件添加新的功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作。

装饰器模式通过嵌套包装多个装饰器对象,可以实现多层次的功能增强。每个具体装饰器类都可以选择性地增加新的功能,同时保持对象接口的一致性。

模式分析

  • 优点
    1. 低耦合:装饰类和被装饰类可以独立变化,互不影响。
    2. 灵活性:可以动态地添加或撤销功能。
    3. 替代继承:提供了一种继承之外的扩展对象功能的方式。
  • 缺点
    1. 复杂性:多层装饰可能导致系统复杂性增加。