-
原理
- 组合与包装
- 基于类或函数组合的装饰器的核心原理是通过组合已有的类或函数来添加新的功能,而不改变被装饰对象的原始结构和接口。它将一个对象(被装饰对象)包裹在另一个对象(装饰器对象)中,装饰器对象与被装饰对象具有相同的接口,这样在使用装饰器对象时,可以在不影响原有代码对被装饰对象调用方式的情况下,扩展或修改被装饰对象的行为。
- 功能增强与职责分离
- 在这种模式下,装饰器类或函数承担了增强功能的职责,将横切关注点(如日志记录、缓存、权限验证等)与被装饰对象的核心功能分离开来。例如,一个基本的文件读取类,其核心功能是从文件中读取数据,而通过装饰器可以为其添加缓存功能,这样在多次读取同一文件时可以提高效率,并且文件读取类本身不需要知道缓存逻辑的存在。
- 组合与包装
-
实现(以 Java 为例)
- 基于类组合的装饰器实现
- 定义接口
- 首先定义一个公共接口,被装饰对象和装饰器都要实现这个接口。例如,定义一个
Component
接口表示可被装饰的组件:
- 首先定义一个公共接口,被装饰对象和装饰器都要实现这个接口。例如,定义一个
- 定义接口
- 基于类组合的装饰器实现
public interface Component {
void operation();
}
- 创建被装饰类
- 实现
Component
接口的被装饰类,它包含了基本的功能。例如:
- 实现
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("执行基本操作");
}
}
- 创建装饰器类
- 装饰器类也实现
Component
接口,并且在内部包含一个被装饰对象的引用。例如:
- 装饰器类也实现
public class Decorator implements Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
// 在调用被装饰对象的方法之前或之后添加额外的逻辑
System.out.println("在操作之前执行额外逻辑");
component.operation();
System.out.println("在操作之后执行额外逻辑");
}
}
- 使用装饰器
- 在客户端代码中,可以这样使用装饰器:
public class Main {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratedComponent = new Decorator(component);
decoratedComponent.operation();
}
}
-
在这个例子中,
Decorator
类是装饰器,它包装了ConcreteComponent
类。当调用decoratedComponent.operation()
时,会先执行装饰器中的前置逻辑,然后调用被装饰对象的operation
方法,最后执行装饰器中的后置逻辑。 -
基于函数组合的装饰器实现(Java 中的函数式接口示例)
- 定义函数式接口
- 在 Java 中,可以利用函数式接口来实现类似的装饰器效果。例如,定义一个函数式接口
FunctionWrapper
:
- 在 Java 中,可以利用函数式接口来实现类似的装饰器效果。例如,定义一个函数式接口
- 定义函数式接口
@FunctionalInterface
public interface FunctionWrapper<T, R> {
R apply(T t);
}
- 创建被装饰函数
- 假设我们有一个简单的函数作为被装饰对象,例如:
public class FunctionExamples {
public static Integer addOne(Integer num) {
return num + 1;
}
}
- 创建装饰器函数
- 通过函数式接口创建装饰器函数,它可以在调用被装饰函数之前或之后添加逻辑。例如,创建一个装饰器函数用于在执行
addOne
函数之前打印信息:
- 通过函数式接口创建装饰器函数,它可以在调用被装饰函数之前或之后添加逻辑。例如,创建一个装饰器函数用于在执行
public class FunctionExamples {
public static FunctionWrapper<Integer, Integer> logBeforeAddOne = num -> {
System.out.println("在执行加一操作之前");
return addOne(num);
};
}
- 使用装饰器函数
- 在客户端代码中使用装饰器函数:
public class Main {
public static void main(String[] args) {
Integer result = logBeforeAddOne.apply(5);
System.out.println("结果: " + result);
}
}
- 在这个例子中,
logBeforeAddOne
函数是一个装饰器函数,它包装了addOne
函数,在调用addOne
函数之前添加了打印信息的逻辑。同样的思路可以用于创建更复杂的装饰器函数,如在函数执行后添加逻辑或者进行多次包装以实现多种功能的组合添加。