装饰器模式(DECORATOR)
装饰器模式解决的是基座+配件灵活组合的问题
装饰器模式是包装器模式中的一种, 它生成最终对象的过程也是包装器对象将包装器层层包裹起来.
装饰器模式需要两个关键角色
基础类: Component + ComponentConcrete
若干包装类: Wrapper + WrapperConcrete1 + WrapperConcrete2 + WrapperConcrete3 + ...
在包装类接口中, 通过类成员引用的方式, 将基础类聚合进来, 再通过包装类层层包裹, 简单实现过程如下:
java
// 基础类统一接口
// 定义统一行为,保证基础类和装饰器行为一致,是装饰器模式的 "契约"
interface Component {
void exec();
}
// 基础类实现
class ConcreteComponent implements Component {
@Override
public void exec() {
System.out.println("ConcreteComponent exec");
}
}
// 装饰器配件抽象类
abstract class Decorator implements Component {
private Component wrap_c; // 这里是基础类的引用, 实现包装类的关键
Decorator(Component c) {
this.wrap_c = c; // 构造时注入基础类, 将在此基础上实现层层包裹
}
@Override
public void exec() {
System.out.println("Decorator exec");
wrap_c.exec(); // 这一步很关键, 基础类对象的exec方法是初始化完成之后链式调用的第一步
}
}
// 配件1
class D1 extends Decorator {
D1(Component c) {
super(c);
}
@Override
public void exec() {
// 一般先执行自己的增强逻辑,再调用被装饰对象的方法
System.out.println("D1");
super.exec();
}
}
// 配件2
class D2 extends Decorator {
D2(Component c) {
super(c);
}
@Override
public void exec() {
System.out.println("D2");
super.exec();
}
}
// 配件3
class D3 extends Decorator {
D3(Component c) {
super(c);
}
@Override
public void exec() {
System.out.println("D3");
super.exec();
}
}
实例化多层对象包裹
java
public class DecoratorPattern {
public static void main(String[] args) {
// 创建基座实例
Component c = new ConcreteComponent();
// 在基座上包裹配件D1, D2, D3
D3 d3 = new D3(new D2(new D1(c)));
d3.exec();
System.out.println("----------- separate line -----------");
// 动态装配, 先实例化基座
Component cc = new ConcreteComponent();
// 随机增加D1, D3两个配件
Component dd1 = new D1(cc);
Component dd3 = new D3(dd1);
dd3.exec();
}
}
运行结果:
D3
Decorator exec
D2
Decorator exec
D1
Decorator exec
ConcreteComponent exec
----------- separate line -----------
D3
Decorator exec
D1
Decorator exec
ConcreteComponent exec
要点:
1. 每个装饰器都只增强,不改变原功能
2. 保持与原接口相同,确保可层层包裹
在实际开发过程中的装饰器模式示例如下
基础类统一接口及基础类实现
java
// 支付服务接口(抽象组件):定义核心支付功能
interface PaymentService {
/**
* 发起支付
* @param userId 用户ID
* @param amount 支付金额(分)
* @param orderId 订单ID
* @return 支付结果(成功/失败)
*/
boolean pay(String userId, long amount, String orderId);
}
// 支付宝支付实现, 基础类
class AlipayPayment implements PaymentService {
@Override
public boolean pay(String userId, long amount, String orderId) {
// 模拟支付宝支付核心逻辑(调用第三方API、扣减余额等)
System.out.printf(
"[支付宝支付] 发起支付 - 用户ID:%s,订单ID:%s,金额:%d分%n",
userId, orderId, amount
);
// 模拟支付成功(实际场景需处理异常和返回结果)
return true;
}
}
定义装饰器抽象类, 装饰器模式的关键
java
// 装饰器抽象类, 聚合基础类引用
abstract class PaymentDecorator implements PaymentService {
// 持有被装饰的核心组件
protected final PaymentService paymentService;
// 构造器注入,确保被装饰对象非空(企业级代码空校验)
public PaymentDecorator(PaymentService paymentService) {
this.paymentService = Objects.requireNonNull(paymentService, "支付服务不能为空");
}
// 子类需实现pay方法,添加装饰功能
@Override
public abstract boolean pay(String userId, long amount, String orderId);
}
3种装饰器配件具体实现
java
// 装饰器配件1, 日志
class LoggingPaymentDecorator extends PaymentDecorator {
public LoggingPaymentDecorator(PaymentService paymentService) {
super(paymentService);
}
@Override
public boolean pay(String userId, long amount, String orderId) {
// 装饰逻辑:支付前记录请求日志
String requestLog = String.format(
"[支付日志] 时间:%s,操作:发起支付,用户ID:%s,订单ID:%s,金额:%d分",
LocalDateTime.now(), userId, orderId, amount
);
System.out.println(requestLog);
// 调用核心支付功能(被装饰对象的方法)
boolean payResult = paymentService.pay(userId, amount, orderId);
// 装饰逻辑:支付后记录结果日志
String resultLog = String.format(
"[支付日志] 时间:%s,操作:支付完成,订单ID:%s,结果:%s",
LocalDateTime.now(), orderId, payResult ? "成功" : "失败"
);
System.out.println(resultLog);
return payResult;
}
}
// 装饰器配件2: 加密
class EncryptionPaymentDecorator extends PaymentDecorator {
public EncryptionPaymentDecorator(PaymentService paymentService) {
super(paymentService);
}
@Override
public boolean pay(String userId, long amount, String orderId) {
// 装饰逻辑:支付前加密参数(模拟AES加密)
String encryptedUserId = encrypt(userId);
String encryptedOrderId = encrypt(orderId);
System.out.printf(
"[加密处理] 原始参数 - 用户ID:%s,订单ID:%s → 加密后 - %s,%s%n",
userId, orderId, encryptedUserId, encryptedOrderId
);
// 调用核心支付功能(传入加密后的参数,实际场景需解密后使用)
boolean payResult = paymentService.pay(encryptedUserId, amount, encryptedOrderId);
// 装饰逻辑:支付后加密返回结果(可选)
System.out.printf("[加密处理] 支付结果加密:%s → %s%n", payResult, encrypt(String.valueOf(payResult)));
return payResult;
}
// 模拟加密算法(实际用AES/RSA)
private String encrypt(String content) {
return "ENC(" + content + "_" + System.currentTimeMillis() + ")";
}
}
// 装饰器配件3: 权限校验
class AuthorizationPaymentDecorator extends PaymentDecorator {
public AuthorizationPaymentDecorator(PaymentService paymentService) {
super(paymentService);
}
@Override
public boolean pay(String userId, long amount, String orderId) {
// 装饰逻辑:支付前校验权限
System.out.printf("[权限校验] 校验用户 %s 是否有权限支付订单 %s%n", userId, orderId);
if (!hasPaymentPermission(userId)) {
System.err.printf("[权限校验] 用户 %s 无支付权限,拒绝支付%n", userId);
return false;
}
System.out.printf("[权限校验] 用户 %s 权限通过%n", userId);
// 调用核心支付功能
return paymentService.pay(userId, amount, orderId);
}
// 模拟权限校验(实际查数据库/缓存)
private boolean hasPaymentPermission(String userId) {
// 假设用户ID以"U"开头的有权限
return userId != null && userId.startsWith("U");
}
}
调用示例
java
import java.time.LocalDateTime;
import java.util.Objects;
public class Decorator {
public static void main(String[] args) {
// 1. 创建原始支付组件(核心功能)
PaymentService rawPayment = new AlipayPayment();
// 2. 动态添加装饰功能(按需组合,顺序可调整)
// 需求:支付前先校验权限 → 加密参数 → 记录日志 → 执行支付
PaymentService decoratedPayment = new AuthorizationPaymentDecorator(
new EncryptionPaymentDecorator(
new LoggingPaymentDecorator(rawPayment)
)
);
// 3. 发起支付(使用装饰后的服务)
boolean result1 = decoratedPayment.pay("U1001", 9999, "ORDER_20251207_001");
}
}
运行输出:
[权限校验] 校验用户 U1001 是否有权限支付订单 ORDER_20251207_001
[权限校验] 用户 U1001 权限通过
[加密处理] 原始参数 - 用户ID:U1001,订单ID:ORDER_20251207_001 → 加密后 - ENC(U1001_1765096216897),ENC(ORDER_20251207_001_1765096216910)
[支付日志] 时间:2025-12-07T16:30:16.924497200,操作:发起支付,用户ID:ENC(U1001_1765096216897),订单ID:ENC(ORDER_20251207_001_1765096216910),金额:9999分
[支付宝支付] 发起支付 - 用户ID:ENC(U1001_1765096216897),订单ID:ENC(ORDER_20251207_001_1765096216910),金额:9999分
[支付日志] 时间:2025-12-07T16:30:16.925494400,操作:支付完成,订单ID:ENC(ORDER_20251207_001_1765096216910),结果:成功
[加密处理] 支付结果加密:true → ENC(true_1765096216925)