软件设计模式-装饰器模式

装饰器模式 Mermaid 类图

装饰器模式序列图

装饰器模式对象关系图

一个装饰器模式的 Java Demo。这个例子将模拟 Java I/O 中的 BufferedReader(FileReader) 结构。

装饰器模式 Java 实现

1. 首先定义组件接口

java复制代码

复制代码
// 组件接口 - 定义基本操作
public interface DataReader {
    String read();
    void close();
}

2. 实现具体组件(被装饰的对象)

java复制代码

复制代码
// 具体组件 - 文件读取器(相当于FileReader)
public class FileReader implements DataReader {
    private String filename;
    
    public FileReader(String filename) {
        this.filename = filename;
        System.out.println("打开文件: " + filename);
    }
    
    @Override
    public String read() {
        // 模拟从文件读取数据
        String data = "原始文件数据 from " + filename;
        System.out.println("读取文件: " + data);
        return data;
    }
    
    @Override
    public void close() {
        System.out.println("关闭文件: " + filename);
    }
}

3. 创建抽象装饰器

java复制代码

复制代码
// 抽象装饰器 - 维持一个指向组件对象的引用
public abstract class DataReaderDecorator implements DataReader {
    protected DataReader decoratedReader;
    
    public DataReaderDecorator(DataReader reader) {
        this.decoratedReader = reader;
    }
    
    @Override
    public String read() {
        return decoratedReader.read();
    }
    
    @Override
    public void close() {
        decoratedReader.close();
    }
}

4. 实现具体装饰器

java复制代码

复制代码
// 具体装饰器 - 缓冲读取器(相当于BufferedReader)
public class BufferedReader extends DataReaderDecorator {
    private StringBuilder buffer;
    private boolean bufferLoaded = false;
    
    public BufferedReader(DataReader reader) {
        super(reader);
        this.buffer = new StringBuilder();
        System.out.println("创建缓冲读取器");
    }
    
    @Override
    public String read() {
        if (!bufferLoaded) {
            // 从被装饰的读取器读取数据并缓冲
            String data = decoratedReader.read();
            buffer.append("【缓冲数据】").append(data).append("【缓冲结束】");
            bufferLoaded = true;
            System.out.println("数据已加载到缓冲区");
        }
        
        // 从缓冲区返回数据
        String result = buffer.toString();
        System.out.println("从缓冲区读取: " + result);
        return result;
    }
    
    // 添加装饰器特有的方法
    public String readLine() {
        String data = read();
        return data + " (按行读取)";
    }
    
    @Override
    public void close() {
        buffer.setLength(0); // 清空缓冲区
        bufferLoaded = false;
        System.out.println("清空缓冲区");
        decoratedReader.close();
    }
}

5. 另一个装饰器示例 - 编码转换器

java复制代码

复制代码
// 另一个具体装饰器 - 编码转换器
public class EncodingReader extends DataReaderDecorator {
    private String encoding;
    
    public EncodingReader(DataReader reader, String encoding) {
        super(reader);
        this.encoding = encoding;
        System.out.println("创建编码转换器: " + encoding);
    }
    
    @Override
    public String read() {
        String originalData = decoratedReader.read();
        String convertedData = "[" + encoding + "编码]" + originalData + "[/" + encoding + "]";
        System.out.println("编码转换: " + convertedData);
        return convertedData;
    }
}

6. 客户端测试类

java复制代码

复制代码
// 客户端代码 - 演示装饰器模式的使用
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        System.out.println("=== 基础文件读取 ===");
        DataReader fileReader = new FileReader("test.txt");
        fileReader.read();
        fileReader.close();
        
        System.out.println("\n=== 添加缓冲功能 ===");
        DataReader bufferedReader = new BufferedReader(new FileReader("test.txt"));
        bufferedReader.read();
        // 可以调用装饰器特有的方法
        if (bufferedReader instanceof BufferedReader) {
            String line = ((BufferedReader) bufferedReader).readLine();
            System.out.println("特有方法调用: " + line);
        }
        bufferedReader.read(); // 第二次读取会使用缓冲区
        bufferedReader.close();
        
        System.out.println("\n=== 多层装饰 ===");
        DataReader advancedReader = new EncodingReader(
            new BufferedReader(
                new FileReader("data.txt")
            ), "UTF-8"
        );
        advancedReader.read();
        advancedReader.close();
        
        System.out.println("\n=== 灵活组合 ===");
        DataReader customReader = new BufferedReader(
            new EncodingReader(
                new FileReader("custom.txt"), "ASCII"
            )
        );
        customReader.read();
        customReader.close();
    }
}

运行结果

复制代码

复制代码
=== 基础文件读取 ===
打开文件: test.txt
读取文件: 原始文件数据 from test.txt
关闭文件: test.txt

=== 添加缓冲功能 ===
打开文件: test.txt
创建缓冲读取器
读取文件: 原始文件数据 from test.txt
数据已加载到缓冲区
从缓冲区读取: 【缓冲数据】原始文件数据 from test.txt【缓冲结束】
特有方法调用: 【缓冲数据】原始文件数据 from test.txt【缓冲结束】 (按行读取)
从缓冲区读取: 【缓冲数据】原始文件数据 from test.txt【缓冲结束】
清空缓冲区
关闭文件: test.txt

=== 多层装饰 ===
打开文件: data.txt
创建缓冲读取器
创建编码转换器: UTF-8
读取文件: 原始文件数据 from data.txt
数据已加载到缓冲区
从缓冲区读取: 【缓冲数据】原始文件数据 from data.txt【缓冲结束】
编码转换: [UTF-8编码]【缓冲数据】原始文件数据 from data.txt【缓冲结束】[/UTF-8]
清空缓冲区
关闭文件: data.txt

=== 灵活组合 ===
打开文件: custom.txt
创建编码转换器: ASCII
创建缓冲读取器
读取文件: 原始文件数据 from custom.txt
编码转换: [ASCII编码]原始文件数据 from custom.txt[/ASCII]
数据已加载到缓冲区
从缓冲区读取: 【缓冲数据】[ASCII编码]原始文件数据 from custom.txt[/ASCII]【缓冲结束】
清空缓冲区
关闭文件: custom.txt

模式要点总结

  1. 组件接口 (DataReader): 定义核心功能
  2. 具体组件 (FileReader): 实现基本功能
  3. 抽象装饰器 (DataReaderDecorator): 维持组件引用,实现相同接口
  4. 具体装饰器 (BufferedReader, EncodingReader): 添加额外功能

装饰器模式的优点:

  • 比继承更灵活,可以动态组合功能
  • 符合开闭原则,无需修改原有代码
  • 可以嵌套多个装饰器

这个例子完美展示了装饰器模式如何"动态地给对象添加额外职责",正如 Java I/O 库的设计理念。

相关推荐
VidDown3 小时前
24fps 转 25fps 不只是改个数字:帧率转换、PAL/NTSC 与音频补偿
python·网络协议·音视频·视频编解码·视频
死磕音视频5 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
凤山老林5 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
pride.li7 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
databook7 小时前
用 Pydantic AI 从零搭建一个能干活的 AI Agent
人工智能·python
康小旺7 小时前
把 markitdown 做成 Windows 桌面版:拖进文档就出 Markdown,附 233MB→64MB 打包裁剪全过程
python
启观川8 小时前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
南笙北梦8 小时前
本地开源大模型多轮对话显存泄漏排查与修复实录
python
小羊没烦恼!9 小时前
如何在IIS6,7中部署ASP.NET网站?
数据库·后端·python·web安全·asp.net
钱栈up9 小时前
扫完 3.5 万文件后,我发现了 521 组散落的同名文件
爬虫·python·数据分析