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

发布于:2025-06-05 ⋅ 阅读:(15) ⋅ 点赞:(0)

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

装饰器模式核心原理

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

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

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

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

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源码:

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集合框架中的装饰器应用
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. 当需要保持被装饰对象的接口纯净时

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

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


网站公告

今日签到

点亮在社区的每一天
去签到