装饰器模式属于结构型设计模式,核心思想是通过创建一个装饰类,包装原有对象,在保持原有对象接口不变的情况下,为其添加新的功能,整个过程不需要修改原有类的源码,符合开闭原则的要求。

装饰器模式的核心角色
一个标准的装饰器模式通常包含以下四个角色:
- 抽象组件(Component):定义一个抽象接口,是所有被装饰对象和装饰对象共同实现的接口,声明了核心的业务方法。
- 具体组件(ConcreteComponent):抽象组件的具体实现类,也就是我们需要扩展功能的基础对象。
- 抽象装饰器(Decorator):实现抽象组件接口,内部持有一个抽象组件的引用,是所有具体装饰器的父类。
- 具体装饰器(ConcreteDecorator):继承抽象装饰器,在调用原有对象方法的基础上,添加自己的扩展逻辑。
实现步骤与代码示例
下面通过一个文件读取的场景来演示装饰器模式的实现:基础的文件读取类只能读取普通文本,我们需要动态给它添加缓存读取和加密读取的功能。
1. 定义抽象组件接口
首先定义文件读取的抽象接口,声明读取文件的核心方法:
// 抽象组件:文件读取接口
public interface FileReader {
String readFile(String filePath);
}
2. 实现具体组件
实现基础的文件读取类,完成最基础的文本读取功能:
// 具体组件:基础文本文件读取类
public class TextFileReader implements FileReader {
@Override
public String readFile(String filePath) {
// 模拟读取文件内容,实际场景中会调用IO流读取文件
return "文件基础内容:" + filePath;
}
}
3. 定义抽象装饰器
抽象装饰器实现抽象组件接口,持有抽象组件的引用,所有具体装饰器都继承这个类:
// 抽象装饰器:文件读取装饰器基类
public abstract class FileReaderDecorator implements FileReader {
// 持有被装饰的对象引用
protected FileReader fileReader;
public FileReaderDecorator(FileReader fileReader) {
this.fileReader = fileReader;
}
@Override
public String readFile(String filePath) {
// 调用被装饰对象的核心方法
return fileReader.readFile(filePath);
}
}
4. 实现具体装饰器
分别实现缓存装饰器和加密装饰器,在原有功能基础上添加扩展逻辑:
// 具体装饰器:缓存读取装饰器
public class CacheFileReaderDecorator extends FileReaderDecorator {
public CacheFileReaderDecorator(FileReader fileReader) {
super(fileReader);
}
@Override
public String readFile(String filePath) {
// 先调用原有读取逻辑
String content = super.readFile(filePath);
// 添加缓存扩展逻辑
return content + " [已添加缓存功能]";
}
}
// 具体装饰器:加密读取装饰器
public class EncryptFileReaderDecorator extends FileReaderDecorator {
public EncryptFileReaderDecorator(FileReader fileReader) {
super(fileReader);
}
@Override
public String readFile(String filePath) {
// 先调用原有读取逻辑
String content = super.readFile(filePath);
// 添加加密扩展逻辑
return content + " [已添加加密功能]";
}
}
5. 使用装饰器动态扩展功能
在客户端代码中,我们可以自由组合装饰器,动态给基础对象添加需要的功能,不需要修改原有类的源码:
public class Client {
public static void main(String[] args) {
// 创建基础文件读取对象
FileReader baseReader = new TextFileReader();
System.out.println("基础读取结果:" + baseReader.readFile("test.txt"));
// 动态添加缓存功能
FileReader cacheReader = new CacheFileReaderDecorator(baseReader);
System.out.println("添加缓存后结果:" + cacheReader.readFile("test.txt"));
// 在缓存功能基础上再添加加密功能
FileReader encryptCacheReader = new EncryptFileReaderDecorator(cacheReader);
System.out.println("添加缓存+加密后结果:" + encryptCacheReader.readFile("test.txt"));
}
}
装饰器模式的优缺点
优点
- 符合开闭原则,不需要修改原有类的源码就能扩展功能,降低代码耦合度。
- 可以动态组合多个装饰器,灵活扩展对象的功能,比继承更加灵活。
- 装饰类和被装饰类相互独立,各自的变化不会影响对方。
缺点
- 如果装饰器嵌套层级过多,会增加代码的复杂度,不利于后期维护。
- 需要额外创建多个装饰类,会增加类的数量,使得系统更复杂。
适用场景
装饰器模式适合以下场景:
- 需要在不修改原有类源码的前提下,给对象动态添加功能。
- 需要给一个对象添加的功能存在多种组合方式,用继承会导致子类数量爆炸的场景。
- 需要为一批兄弟类添加通用的扩展功能,又不想修改这些类的源码的场景。