1. 概述

装饰器模式(Decorator Pattern) 可以在运行时为对象添加额外的功能,无论是静态还是动态的。它提供了一种比继承更灵活的方式,在不修改原始类的情况下增强对象的行为。

这个模式的核心思想是:组合优于继承。通过递归式的包装结构,我们可以一层层地给对象“加料”,而不需要为每一种组合都创建一个子类。

2. 装饰器模式示例

我们以一棵圣诞树为例。假设我们要对这棵树进行装饰,比如加上彩带、亮片、星星、灯泡等。这些装饰并不会改变树本身,只是让它看起来更漂亮。

8poz64T

在这个场景中,我们将遵循《设计模式:可复用面向对象软件的基础》(Gang of Four)中的命名规范和结构。

2.1 定义基础组件接口

首先定义 ChristmasTree 接口:

public interface ChristmasTree {
    String decorate();
}

接着是它的默认实现:

public class ChristmasTreeImpl implements ChristmasTree {

    @Override
    public String decorate() {
        return "Christmas tree";
    }
}

2.2 创建抽象装饰器

然后创建一个抽象装饰器类 TreeDecorator,它实现了 ChristmasTree 接口,并持有一个 ChristmasTree 实例:

public abstract class TreeDecorator implements ChristmasTree {
    private ChristmasTree tree;

    public TreeDecorator(ChristmasTree tree) {
        this.tree = tree;
    }

    @Override
    public String decorate() {
        return tree.decorate();
    }
}

2.3 具体装饰器实现

接下来是一些具体的装饰器类,例如灯泡装饰:

public class BubbleLights extends TreeDecorator {

    public BubbleLights(ChristmasTree tree) {
        super(tree);
    }

    public String decorate() {
        return super.decorate() + decorateWithBubbleLights();
    }

    private String decorateWithBubbleLights() {
        return " with Bubble Lights";
    }
}

还有一个彩带装饰器(为了完整性补充):

public class Garland extends TreeDecorator {

    public Garland(ChristmasTree tree) {
        super(tree);
    }

    public String decorate() {
        return super.decorate() + decorateWithGarland();
    }

    private String decorateWithGarland() {
        return " with Garland";
    }
}

2.4 使用装饰器

现在我们可以灵活地组合装饰器来生成不同的装饰效果:

@Test
public void whenDecoratorsInjectedAtRuntime_thenConfigSuccess() {
    ChristmasTree tree1 = new Garland(new ChristmasTreeImpl());
    assertEquals(tree1.decorate(), 
      "Christmas tree with Garland");
     
    ChristmasTree tree2 = new BubbleLights(
      new Garland(new Garland(new ChristmasTreeImpl())));
    assertEquals(tree2.decorate(), 
      "Christmas tree with Garland with Garland with Bubble Lights");
}

⚠️ 注意看上面的例子:

  • tree1 只被一个 Garland 包装。
  • tree2 则被层层包装:两层 Garland + 一层 BubbleLights

这就是装饰器模式的魅力:运行时动态组合行为,而无需预先定义所有可能的组合

3. 总结

装饰器模式适用于以下几种情况:

✅ 当你需要在运行时动态地给对象添加功能或修改其行为
✅ 当你不想通过继承来扩展类(因为会导致类爆炸)
✅ 当你需要对单个对象进行增强而不影响其他实例

如果你觉得继承太死板,或者想避免大量的子类膨胀,装饰器模式是一个非常实用的选择。

📦 本例完整代码见 GitHub:design-patterns-structural


原始标题:The Decorator Pattern in Java