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

装饰器模式是一种极具弹性的结构型设计模式,它允许我们通过组合的方式动态扩展对象功能而无需修改原有结构。本文将通过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. 当需要保持被装饰对象的接口纯净时

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值