自学教程 学编程从这里开始

装饰模式

《装饰器模式》|设计模式系列第10篇

系列:结构型模式 · 装饰器模式(Decorator Pattern)
关键词:动态增强、包装、职责叠加、替代继承、装饰器、组件

一、什么是装饰器模式

装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

属于结构型设计模式。

简单理解:
装饰器就是动态包装原有对象,在不修改原类代码、不使用继承的前提下,给对象叠加新能力。可以多层嵌套包装,随时增加或者移除功能。例如:一杯基础咖啡,可以动态加牛奶、加糖、加奶泡,自由组合配料,而不是创建大量子类(咖啡+牛奶、咖啡+糖、咖啡+牛奶+糖)。

核心意图
动态扩展对象功能;将扩展逻辑从主体类分离,支持功能多层叠加。

适用场景

  1. 需要动态给对象增加/移除功能
  2. 不想使用继承扩展,避免子类数量爆炸
  3. 功能可以自由组合叠加
  4. 主体类本身稳定,功能点零散多变

⚠️ 缺点预警:多层包装后,对象层次变多,调试困难;产生大量小包装类。

二、UML结构图

角色划分:

  1. Component(抽象组件):定义核心接口,被装饰对象和装饰器都实现该接口
  2. ConcreteComponent(具体组件):原始对象,基础核心功能
  3. Decorator(抽象装饰器):继承/实现Component,持有Component引用,包装原始对象
  4. ConcreteDecorator(具体装饰器):实现装饰器,添加额外职责

三、Java 完整示例

场景:Coffee 咖啡,基础咖啡为主体,Milk、Sugar 作为装饰配料,动态叠加。
全部变量、输出文字使用英文。

1. Component 抽象组件

public interface Coffee {
    String getDescription();
    double getPrice();
}

2. ConcreteComponent 具体组件

public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Simple Coffee";
    }

    @Override
    public double getPrice() {
        return 2.0;
    }
}

3. Decorator 抽象装饰器

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

4. ConcreteDecorator 具体装饰器

// Milk Decorator
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }

    @Override
    public double getPrice() {
        return coffee.getPrice() + 0.5;
    }
}

// Sugar Decorator
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }

    @Override
    public double getPrice() {
        return coffee.getPrice() + 0.3;
    }
}

5. Client 客户端

public class Client {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " | Price: " + coffee.getPrice());

        // add milk
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " | Price: " + coffee.getPrice());

        // add sugar
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " | Price: " + coffee.getPrice());
    }
}

运行输出:

Simple Coffee | Price: 2.0
Simple Coffee, Milk | Price: 2.5
Simple Coffee, Milk, Sugar | Price: 2.8

可以自由多层嵌套,动态增加任意组合的配料,不需要新建大量咖啡子类。

四、装饰器模式 vs 适配器模式

模式目标核心
Decorator增强原有对象能力,接口不变包装对象,叠加新功能
Adapter转换对象接口,改变接口包装对象,适配不兼容接口

五、优缺点总结

✅ 优点

  1. 动态扩展对象功能,运行时自由增加、移除职责
  2. 功能拆分,每个装饰器只负责单一能力,符合单一职责
  3. 避免继承带来的类爆炸,功能自由组合
  4. 主体代码无需改动,符合开闭原则

❌ 缺点

  1. 多层嵌套包装,调试、排查问题比较麻烦
  2. 会生成很多小装饰类,增加代码阅读成本
  3. 装饰顺序会影响最终结果,需要留意

六、框架源码应用

  • JDK IO 流:InputStream / OutputStream,BufferedInputStream、DataInputStream 就是装饰器
  • Spring TransactionAwareCacheDecorator
  • Servlet HttpServletRequestWrapper

七、小结

装饰器核心:包装原始对象,接口保持不变,动态叠加功能,组合替代继承。
判断要点:想给对象动态叠加多个可选能力,优先装饰器;如果目的是转换接口,则用适配器。

标签:

0 条笔记