【设计模式】装饰者模式详解

文章目录

    • [1. 引言:继承真的能解决扩展问题吗?](#1. 引言:继承真的能解决扩展问题吗?)
    • [2. 什么是装饰者模式](#2. 什么是装饰者模式)
      • [GoF 定义](#GoF 定义)
    • [3. 装饰者模式的核心思想](#3. 装饰者模式的核心思想)
    • [4. 装饰者模式的角色组成](#4. 装饰者模式的角色组成)
    • [5. 示例场景:咖啡加料系统](#5. 示例场景:咖啡加料系统)
      • [5.1 抽象组件](#5.1 抽象组件)
      • [5.2 具体组件](#5.2 具体组件)
      • [5.3 抽象装饰者](#5.3 抽象装饰者)
      • [5.4 具体装饰者](#5.4 具体装饰者)
      • [5.5 客户端使用](#5.5 客户端使用)
    • [6. 装饰顺序的重要⭐](#6. 装饰顺序的重要⭐)
    • [7. 装饰者模式的优点](#7. 装饰者模式的优点)
    • [8. 装饰者模式的缺点](#8. 装饰者模式的缺点)
    • [9. 装饰者 vs 代理 vs 适配器](#9. 装饰者 vs 代理 vs 适配器)
    • [10. JDK 中的装饰者模式](#10. JDK 中的装饰者模式)
      • [Java IO 体系](#Java IO 体系)
    • [11. 适用场景](#11. 适用场景)
    • [12. 一个常见误区](#12. 一个常见误区)
    • 参考

1. 引言:继承真的能解决扩展问题吗?

假设我们有一个简单的咖啡类:

java 复制代码
class Coffee {
    double cost() {
        return 10;
    }
}

如果现在要支持:

  • 加牛奶
  • 加糖
  • 加奶泡
  • 任意组合

你可能会想到继承:

  • MilkCoffee
  • SugarCoffee
  • MilkSugarCoffee
  • MilkSugarFoamCoffee ...

问题很快就出现了:

  • 类数量爆炸
  • 组合不灵活
  • 扩展困难

当继承开始失控时,就该考虑装饰者模式了。

装饰者模式解决的核心问题是:

如何在不修改原类的前提下,灵活地为对象增加功能。


2. 什么是装饰者模式

GoF 定义

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

在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

一句话理解:

装饰者模式 = 用"组合"代替"继承"来扩展功能。


3. 装饰者模式的核心思想

装饰者模式的本质在于:

  • 不修改原有类
  • 不通过继承增加功能
  • 在运行期动态叠加功能

核心原则:

对扩展开放,对修改关闭。


4. 装饰者模式的角色组成

装饰者模式通常包含四个角色:

  1. 抽象组件(Component)

定义一个抽象接口以规范准备接收附加责任的对象。

  1. 具体组件(ConcreteComponent)

实现抽象构件,通过装饰角色为其添加一些职责。

  1. 抽象装饰者(Decorator)

继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。

  1. 具体装饰者(ConcreteDecorator)

实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。


5. 示例场景:咖啡加料系统

5.1 抽象组件

java 复制代码
public interface Beverage {
    double cost();
    String getDescription();
}

5.2 具体组件

java 复制代码
public class Coffee implements Beverage {

    @Override
    public double cost() {
        return 10;
    }

    @Override
    public String getDescription() {
        return "咖啡";
    }
}

5.3 抽象装饰者

java 复制代码
// 注意:这里没有实现cost()方法和getDescription()方法,所以必须是抽象类
public abstract class BeverageDecorator implements Beverage {

    protected Beverage beverage; 

    public BeverageDecorator(Beverage beverage) {
        this.beverage = beverage;
    }
}

protected Beverage beverage; 注意这里,如果没明白可以理解为Beverage beverage=new MilkDecorator();多态实现的形式


5.4 具体装饰者

牛奶装饰者
java 复制代码
public class MilkDecorator extends BeverageDecorator {

    public MilkDecorator(Beverage beverage) {
        super(beverage);
    }

    @Override
    public double cost() {
        return beverage.cost() + 2;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 牛奶";
    }
}
糖装饰者
java 复制代码
public class SugarDecorator extends BeverageDecorator {

    public SugarDecorator(Beverage beverage) {
        super(beverage);
    }

    @Override
    public double cost() {
        return beverage.cost() + 1;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 糖";
    }
}

5.5 客户端使用

java 复制代码
Beverage beverage = new Coffee();
beverage = new MilkDecorator(beverage);
beverage = new SugarDecorator(beverage);

System.out.println(beverage.getDescription());
System.out.println(beverage.cost());

输出结果:


6. 装饰顺序的重要⭐

java 复制代码
beverage = new SugarDecorator(new MilkDecorator(new Coffee()));
  • 装饰顺序不同
  • 行为和结果可能不同

装饰者模式支持功能的"叠加"和"组合"。


7. 装饰者模式的优点

  1. 避免类爆炸
  2. 功能扩展灵活
  3. 支持运行期动态组合
  4. 符合开闭原则
  5. 比继承更灵活

8. 装饰者模式的缺点

  1. 类数量增加
  2. 调试困难
  3. 调用链变长
  4. 结构理解成本较高

9. 装饰者 vs 代理 vs 适配器

模式 核心目的
装饰者 动态扩展功能
代理 控制访问
适配器 接口转换

结构相似,意图不同。


10. JDK 中的装饰者模式

Java IO 体系

java 复制代码
InputStream in =
    new BufferedInputStream(
        new DataInputStream(
            new FileInputStream("test.txt")
        )
    );
  • FileInputStream:基础功能
  • BufferedInputStream:缓存
  • DataInputStream:数据解析

👉 经典装饰者模式示例


11. 适用场景

适合使用

  • 功能可以自由组合
  • 扩展方式多样
  • 不希望使用继承
  • 框架、基础组件设计

不适合使用

  • 功能极其简单
  • 扩展点非常少
  • 对性能极端敏感

12. 一个常见误区

装饰者模式不是"为了多写几层包装",而是为了"组合能力"。


参考

装饰器模式 | 菜鸟教程

装饰模式-百度百科

《图解设计模式》

装饰器 - Java教程 - 廖雪峰的官方网站

适配器设计模式(封装器模式)

相关推荐
vx-bot55566620 小时前
企业微信接口在自动化工作流中的关键角色与设计模式
设计模式·自动化·企业微信
Yu_Lijing20 小时前
基于C++的《Head First设计模式》笔记——工厂模式
c++·笔记·设计模式
HL_风神1 天前
设计原则之迪米特
c++·学习·设计模式
HL_风神1 天前
设计原则之合成复用
c++·学习·设计模式
Aeside12 天前
揭秘 Nginx 百万并发基石:Reactor 架构与 Epoll 底层原理
后端·设计模式
帅气的你2 天前
从零封装一个通用的 API 接口返回类:统一前后端交互格式
java·设计模式
阿里巴巴淘系技术团队官网博客2 天前
GenAI输出内容控制的5种设计模式
设计模式
沛沛老爹2 天前
Skills高级设计模式(一):向导式工作流与模板生成
java·人工智能·设计模式·prompt·aigc·agent·web转型
__万波__2 天前
二十三种设计模式(二十二)--策略模式
java·设计模式·策略模式