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

装饰器模式 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 库的设计理念。

相关推荐
闲人编程2 小时前
Python的导入系统:模块查找、加载和缓存机制
java·python·缓存·加载器·codecapsule·查找器
weixin_457760002 小时前
Python 数据结构
数据结构·windows·python
合作小小程序员小小店3 小时前
web网页,在线%抖音,舆情,线性回归%分析系统demo,基于python+web+echart+nlp+线性回归,训练,数据库mysql
python·自然语言处理·回归·nlp·线性回归
q***2513 小时前
Python中的简单爬虫
爬虫·python·信息可视化
最晚的py3 小时前
Python Matplotlib
python·数据分析
柳鲲鹏3 小时前
OpenCV:文件视频防抖,python版
python·opencv·音视频
phdsky4 小时前
【设计模式】代理模式
设计模式·代理模式
@sinner5 小时前
你好,Scikit-learn:从零开始你的第一个机器学习项目
python·机器学习·scikit-learn