从Java的JDK源码中学设计模式之装饰器模式

装饰器模式是一种极具弹性的结构型设计模式,它允许我们通过组合的方式动态扩展对象功能而无需修改原有结构。本文将通过JDK源码中的实际应用和通俗易懂的代码示例,带你深入了解这一强大模式的精髓。

装饰器模式核心原理

装饰器模式的核心思想:在原有对象外面"包装"一层新功能,同时保持与被装饰对象相同的接口。它能够:

  1. 在不改变对象的前提下增强功能
  2. 避免因过度继承导致类爆炸
  3. 支持运行时动态添加功能
  4. 组合替代继承提高灵活性

Java IO包中的装饰器模式实战

让我们深入JDK源码(Java 17),看看java.io包如何完美应用装饰器模式:

java 复制代码
import java.io.*;

public class DecoratorInJavaIO {
    public static void main(String[] args) throws IOException {
        // 基础数据类型装饰
        DataInputStream dataInput = new DataInputStream(
            new BufferedInputStream(
                new FileInputStream("data.bin")
            )
        );
      
        // 字符编码转换装饰
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(
                new FileInputStream("text.txt"), "UTF-8"
            )
        );
      
        // 动态添加行号功能
        LineNumberReader lineReader = new LineNumberReader(reader);
      
        // 动态添加大小写转换装饰器
        UpperCaseReader upperReader = new UpperCaseReader(lineReader);
      
        String line;
        while ((line = upperReader.readLine()) != null) {
            int num = upperReader.getLineNumber();
            System.out.println("Line " + num + ": " + line);
        }
    }
}

// 自定义装饰器:将内容转为大写
class UpperCaseReader extends FilterReader {
    protected UpperCaseReader(Reader in) {
        super(in);
    }
  
    @Override
    public int read() throws IOException {
        int c = super.read();
        return (c == -1) ? c : Character.toUpperCase(c);
    }
  
    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        int n = super.read(cbuf, off, len);
        for (int i = off; i < off + n; i++) {
            cbuf[i] = Character.toUpperCase(cbuf[i]);
        }
        return n;
    }
  
    // 增强功能:提供读取整行的方法
    public String readLine() throws IOException {
        char[] buffer = new char[1024];
        int pos = 0;
        int c;
      
        while ((c = read()) != -1) {
            if (c == '\n') break;
            buffer[pos++] = (char)c;
        }
      
        if (pos == 0 && c == -1) return null;
        return new String(buffer, 0, pos);
    }
}

在上述代码中:

  1. 我们使用Java IO的核心装饰器(BufferedInputStream, InputStreamReader)
  2. 展示了装饰器链式组合的强大功能
  3. 创建了自定义的装饰器UpperCaseReader来扩展原有功能

装饰器模式结构解析

下面使用Mermaid工具展示装饰器模式的类图结构:
持有引用 Component +operation() : void ConcreteComponent +operation() : void Decorator -component: Component +Decorator(Component) +operation() : void ConcreteDecoratorA +operation() : void +addedBehavior() : void ConcreteDecoratorB +addedState: String +operation() : void

图中关键角色:

  1. Component: 被装饰对象的公共接口(如Java的InputStream)
  2. ConcreteComponent: 基础实现(如FileInputStream)
  3. Decorator: 装饰器抽象层(如FilterInputStream)
  4. ConcreteDecorator: 具体装饰器实现(如BufferedInputStream)

JDK中装饰器模式实现原理

分析java.io.FilterInputStream源码:

java 复制代码
public class FilterInputStream extends InputStream {
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    public int read() throws IOException {
        return in.read();
    }

    // 所有方法都委托给in对象
    public int read(byte[] b) throws IOException {
        return read(b, 0, b.length);
    }
  
    public int read(byte[] b, int off, int len) throws IOException {
        return in.read(b, off, len);
    }
  
    // 其他方法...
}

在JDK实现中:

  1. 所有具体装饰器都继承自FilterInputStream
  2. 每个装饰器持有底层InputStream的引用
  3. 基础方法直接委托给底层流
  4. 需要增强的方法被重写(如BufferedInputStream缓冲功能)

装饰器模式 vs 继承

特点 装饰器模式 继承
扩展方式 运行时 编译时
组合方式 对象组合 类继承
灵活性 高(动态组合) 低(静态绑定)
功能叠加 线性添加 只能单一路径
修改风险 无(不修改原类) 需要修改类层次

装饰器模式的典型应用场景

  1. 输入/输出流处理:Java IO/NIO中的流装饰
  2. Servlet API:HttpServletRequestWrapper装饰请求
  3. Collections工具类:unmodifiableXXX创建不可变视图
  4. JavaFX应用:Node对象的多种样式装饰
java 复制代码
// Java集合框架中的装饰器应用
List<String> origin = new ArrayList<>();
List<String> safeList = Collections.checkedList(origin, String.class);
List<String> unmodifiable = Collections.unmodifiableList(origin);

装饰器模式的优点与局限

核心优势:

  • 符合开闭原则:扩展不修改
  • 职责明确:小类单一职责
  • 动态组合:运行时装配功能
  • 避免类爆炸:取代多层继承结构

潜在缺点:

  • 过度使用导致结构复杂
  • 调试困难(调用链路深)
  • 小对象数量可能增加

总结与最佳实践

装饰器模式在Java核心库特别是IO系统中发挥了至关重要的作用。它通过优雅的包装机制,实现了功能的动态组合,避免了传统继承的固有问题。

使用建议:

  1. 当需要动态、透明地添加职责时
  2. 当不适合使用子类扩展时
  3. 当目标可能有多种不同组合时
  4. 当需要保持被装饰对象的接口纯净时

掌握装饰器模式将使你的设计更具弹性,帮助创建更灵活、可扩展的系统架构。同时也要注意避免过度装饰导致的复杂性,在恰当的场景发挥其最大价值。

设计思想的精髓: 组合优于继承,封闭修改打开扩展,通过对象包装而非类继承来实现功能增强!

相关推荐
mjhcsp9 分钟前
DeepSeek V4.1 Flash 批量处理效能实测
java·前端·数据库
海绵宝宝转agent41 分钟前
操作系统八股开源笔记分享
java·面试
殷色玫瑰1 小时前
C++ string类详解:常用接口、字符串操作与模拟实现
java·linux·c语言·开发语言·数据结构·c++
CHEEVEN_QY1 小时前
新能源汽车电池托盘FSW量产的工艺稳定性控制
java·前端·汽车
惊讶的猫1 小时前
MCP-server
java
ZealSinger1 小时前
Boot4升级PostConstruct不跑了
java·spring boot·spring·升级迁移
Code_Solitude2 小时前
C语言:关于二维数组的作业总结
java·c语言·前端
Wang's Blog2 小时前
Java 项目实战: 外卖平台优化-Nginx六种负载均衡策略对比与选型
java·nginx·负载均衡
Wang's Blog2 小时前
Java 项目实战: 外卖平台优化-YApi接口管理平台与文档导入导出
java·开发语言·yapi
专业程序开发源2 小时前
django新闻推荐系统70655-计算机课程设计、毕业设计
java·javascript·spring boot·后端·python·django·课程设计