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

文章目录

    • [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教程 - 廖雪峰的官方网站

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

相关推荐
YigAin1 小时前
Unity23种设计模式之 享元模式
设计模式·享元模式
范纹杉想快点毕业14 小时前
实战级ZYNQ中断状态机FIFO设计
java·开发语言·驱动开发·设计模式·架构·mfc
茂桑18 小时前
DDD领域驱动设计-基础设施层
设计模式·架构
小温冲冲1 天前
通俗且全面精讲工厂设计模式
设计模式
进击的小头1 天前
设计模式与C语言高级特性的结合
c语言·设计模式
小温冲冲1 天前
通俗且全面精讲单例设计模式
开发语言·javascript·设计模式
Vivienne_ChenW1 天前
DDD领域模型在项目中的实战
java·开发语言·后端·设计模式
sg_knight1 天前
原型模式(Prototype)
python·设计模式·开发·原型模式
短剑重铸之日1 天前
《设计模式》第九篇:三大类型之结构型模式
java·后端·设计模式·组合模式·代理模式·结构性模式
忧郁的Mr.Li1 天前
设计模式--单例模式
javascript·单例模式·设计模式