一、装饰器模式(Decorator Pattern)

1、模式概述

装饰器模式 是一种 结构型设计模式,它允许 动态地给一个对象添加额外的职责,而不改变其原有结构。装饰器通过 组合 + 委托 的方式,在运行时灵活扩展对象功能。

核心思想“不改类,只加层 —— 功能层层叠加,行为动态增强。”

装饰器模式 = 接口一致 + 组合增强

  • 它不是“硬编码功能”,而是“像搭积木一样动态组装行为”。

2、使用场景

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

  • 需要在 不修改原类代码的前提下,动态地为对象 增加新功能
  • 功能组合 种类繁多,若用继承会导致 类爆炸(如 3 种基础图形 × 4 种边框 × 5 种填充 = 60 个子类);
  • 需要 在运行时动态决定对象的行为(如根据用户权限添加日志、加密等);
  • 希望 复用功能模块,并能 自由组合(如 I/O 流中的 BufferedInputStream 包装 FileInputStream)。

典型应用

  • Java I/O 流体系:BufferedInputStream, DataInputStream 等;
  • Web 开发中的请求/响应包装(如 Spring 的 HttpServletRequestWrapper);
  • 游戏装备系统(武器 + 火焰附魔 + 暴击附魔);
  • UI 控件样式叠加(按钮 + 圆角 + 阴影 + 动画)。

3、示例程序:图形绘制 + 边框装饰

1)抽象构件 Shape

/**
 * 抽象构件(Component)
 * 定义所有图形的公共行为
 */
public interface Shape {
    void draw();
}

2)具体构件(基础图形)

a、圆形

/**
 * 具体构件(ConcreteComponent)
 */
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Circle");
    }
}

b、矩形

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Rectangle");
    }
}

c、装饰器抽象类 ShapeDecorator

  • 构造函数注入被装饰对象;
  • 默认行为是 直接委托,子类可 重写以增强
/**
 * 装饰器抽象类(Decorator)
 * 持有被装饰对象的引用,并实现相同接口
 */
public abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {
        this.decoratedShape = decoratedShape;
    }

    @Override
    public void draw() {
        decoratedShape.draw(); // 委托给被装饰对象
    }
}

4)具体装饰器:红色边框

/**
 * 具体装饰器(ConcreteDecorator)
 * 为图形添加红色边框
 */
public class RedShapeDecorator extends ShapeDecorator {

    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        // 先绘制原始图形
        decoratedShape.draw();
        // 再添加装饰行为
        setRedBorder();
    }

    private void setRedBorder() {
        System.out.println("Border Color: Red");
    }
}

5)客户端测试 Main

  • 同一套装饰器可用于 任意图形

  • 新增装饰(如绿色边框、虚线边框)无需修改现有代码
  • 支持 多层嵌套装饰(如红边 + 虚线 + 阴影)。
/**
 * 客户端(Client)
 * 演示装饰器的动态组合能力
 */
public class Main {
    public static void main(String[] args) {
        // 1. 原始圆形
        Shape circle = new Circle();
        System.out.println("=== 普通圆形 ===");
        circle.draw();

        // 2. 红色边框圆形
        Shape redCircle = new RedShapeDecorator(new Circle());
        System.out.println("\n=== 红色边框圆形 ===");
        redCircle.draw();

        // 3. 红色边框矩形
        Shape redRectangle = new RedShapeDecorator(new Rectangle());
        System.out.println("\n=== 红色边框矩形 ===");
        redRectangle.draw();

        // 4. 叠加装饰(示例:未来可扩展 GreenBorderDecorator)
        // Shape fancyCircle = new GreenBorderDecorator(new RedShapeDecorator(new Circle()));
    }
}

输出:

=== 普通圆形 ===
Shape: Circle

=== 红色边框圆形 ===
Shape: Circle
Border Color: Red

=== 红色边框矩形 ===
Shape: Rectangle
Border Color: Red

6)UML 类图

                ┌──────────────┐
                │   Shape      │
                │--------------│
                │ + draw()     │
                └──────▲───────┘
                       │
       ┌───────────────┴───────────────┐
       │                               │
┌──────▼───────┐           ┌──────────▼────────────┐
│   Circle     │           │    ShapeDecorator     │
│   Rectangle  │           │-----------------------│
└──────────────┘           │ - decoratedShape: Shape│
                           │-----------------------│
                           │ + draw()              │
                           └──────────▲────────────┘
                                      │
                      ┌───────────────┴───────────────┐
                      │                               │
            ┌─────────▼─────────┐         ┌───────────▼────────────┐
            │ RedShapeDecorator │         │ GreenBorderDecorator   │
            │-------------------│         │------------------------│
            │ + draw()          │         │ + draw()               │
            └───────────────────┘         └────────────────────────┘

4、FQA

1)与适配器模式的区别

  • 适配器是为了“能用”

  • 装饰器是为了“更好用”

模式 目的 是否改变接口 典型用途
适配器(Adapter) 转换接口,使不兼容的类能协同工作 ✅ 改变(适配成目标接口) 集成旧系统、第三方库
装饰器(Decorator) 增强功能,保持原有接口不变 ❌ 不改变(完全透明) 日志、权限、缓存、UI 样式等

2)模式优点

  • 开闭原则:新增功能只需添加新装饰器,无需修改原有代码;

  • 灵活性高:可在运行时动态组合功能;

  • 避免类爆炸:相比继承,组合更轻量;

  • 单一职责:每个装饰器只负责一个功能。

3)注意事项

  • 调试复杂度增加:多层嵌套可能导致调用栈过深;
  • 过度设计风险:若功能固定且简单,直接继承更直观;
  • 对象类型识别困难:客户端无法直接知道被装饰了多少层(除非暴露内部结构)。