二十三种设计模式(八)--装饰器模式

装饰器模式(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)
相关推荐
言慢行善21 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星21 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟21 小时前
操作系统之虚拟内存
java·服务器·网络
Tong Z21 小时前
常见的限流算法和实现原理
java·开发语言
凭君语未可21 小时前
Java 中的实现类是什么
java·开发语言
He少年21 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
克里斯蒂亚诺更新1 天前
myeclipse的pojie
java·ide·myeclipse
迷藏4941 天前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏4941 天前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链
qq_433502181 天前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书