Java虽无原生装饰器语法,但可通过Function等函数式接口与andThen/compose链式组合实现日志、权限、重试等动态增强,支持参数化封装与方法引用包装,满足开闭原则和关注分离。

Java 中没有原生的装饰器语法,但可以通过函数式接口 + 高阶函数(接收或返回函数的函数)组合实现类似装饰器的效果:在不修改原始逻辑的前提下,动态增强行为,比如添加日志、权限校验、重试、缓存等。
用 Function/UnaryOperator 等函数式接口定义“增强逻辑”
选择合适的函数式接口是关键。常用的是:
-
Function
:用于有输入输出的转换型增强(如加日志后返回结果) -
UnaryOperator
:当输入输出类型相同时的简化版 Function(如字符串处理) -
Consumer
:适合无返回值的副作用增强(如记录执行耗时) -
Supplier
+ Runnable:配合延迟执行或包装执行流程
例如,定义一个通用的日志装饰器:
public static <t> Function<t t> withLogging(String desc) {
return t -> {
System.out.println("【开始】" + desc + ",输入:" + t);
T result = t; // 这里可插入实际处理(或传入下游函数)
System.out.println("【完成】" + desc + ",输出:" + result);
return result;
};
}</t></t>链式组合:用 andThen 或 compose 实现多层装饰
函数式接口内置了 andThen(后置增强)和 compose(前置增强),天然支持装饰器链:
// 原始业务逻辑
Function<string string> toUpper = s -> s.toUpperCase();
Function<string string> addPrefix = s -> "[DECORATED] " + s;
<p>// 类似 @Log @Validate @Cache 的叠加效果
Function<string string> decorated = toUpper
.andThen(withLogging("转大写"))
.andThen(addPrefix)
.andThen(withLogging("添加前缀"));</string></p>
<p>String result = decorated.apply("hello");
// 输出日志 + 返回 "[DECORATED] HELLO"
</p></string></string>这种组合方式清晰表达了“原始行为 → 增强1 → 增强2”的顺序,语义接近 Python 的 @decorator 叠加。
封装成可复用的装饰器工厂(带参数、可配置)
真实场景中,装饰器常需参数(如超时时间、角色权限)。可封装为静态方法或工具类:
public class Decorators {
// 权限检查装饰器:只有 admin 才放行
public static <t> Function<t t> requireRole(String role) {
return t -> {
if (!"admin".equals(System.getProperty("user.role"))) {
throw new SecurityException("缺少角色: " + role);
}
return t;
};
}
<pre class="brush:php;toolbar:false;">// 重试装饰器(简单版)
public static <t> Function<supplier>, T> withRetry(int maxRetries) {
return supplier -> {
for (int i = 0; i <p>}</p>
<p>// 使用
Function<string string> safeProcess = s -> {
if (s.isEmpty()) throw new RuntimeException("空输入");
return "processed: " + s;
};</string></p>
<p>String result = Decorators.withRetry(2)
.apply(() -> safeProcess.apply("test"));
</p></supplier></t>与实际业务方法结合:用方法引用 + 装饰器包装
不修改原有方法,仅在调用处增强:
public class UserService {
public User findById(Long id) { /* DB 查询 */ }
public void updateUser(User user) { /* 更新逻辑 */ }
}
<p>// 包装成函数式对象
Function<long user> findUser = userService::findById;
Function<long user> loggedFindUser = findUser.andThen(u -> {
System.out.println("查到用户:" + u.getName());
return u;
});</long></long></p><p>// 或统一装饰
Function<long user> cachedFindUser = Decorators.withCache(
userId -> userService.findById(userId),
5_000 // 缓存 5 秒
);
</long></p>这样既保持业务方法干净,又通过组合灵活注入横切关注点,达到装饰器模式的核心目标:开闭原则 + 关注分离。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











