PHP 设计模式 | 责任链模式

62 阅读3分钟

1. 引言

在开发过程中,我们经常会遇到一系列需要按顺序执行的操作,比如日志记录、权限校验、数据过滤等。如果使用 if-else 结构来处理,代码会变得冗长且难以维护。这时,我们可以使用 责任链模式(Chain of Responsibility Pattern) ,将请求沿着一条处理链进行传递,直到某个处理者完成任务或整条链执行完毕。

2. 核心概念

责任链模式的核心思想是 将请求沿着处理者链传递,每个处理者可以选择处理请求或将其传递给下一个处理者。这样可以降低耦合度,并提高代码的灵活性。

核心角色:

  1. 抽象处理者(Handler): 定义处理请求的接口,并存储对下一个处理者的引用。
  2. 具体处理者(ConcreteHandler): 具体的请求处理逻辑,决定是否处理请求或传递给下一个处理者。
  3. 客户端(Client): 构建处理者链并触发请求。

3. 适用场景

  • 责任链任务处理: 例如,中间件拦截 HTTP 请求,按顺序执行权限校验、数据过滤等操作。
  • 日志处理: 例如,不同级别的日志(DEBUG、INFO、ERROR)由不同的处理者处理。
  • 数据校验: 例如,表单提交时,依次检查数据完整性、格式合法性、安全性等。

4. 责任链模式的实现步骤

  1. 定义抽象处理者类,包含 setNext() 方法设置下一个处理者。
  2. 创建具体处理者,实现处理逻辑,并决定是否继续传递请求。
  3. 构建处理链,并触发请求。

5. 代码示例

场景:用户请求经过一系列拦截器(权限校验、数据过滤、日志记录)后才被处理。

<?php

/**
 * 抽象处理者(Handler):定义处理请求的接口
 */
abstract class Handler {
    protected ?Handler $nextHandler = null;

    // 设置下一个处理者
    public function setNext(Handler $handler): Handler {
        $this->nextHandler = $handler;
        return $handler; // 允许链式调用
    }

    // 处理请求的方法,子类需实现
    abstract public function handle(string $request);
}

/**
 * 具体处理者 1:权限校验
 */
class AuthHandler extends Handler {
    public function handle(string $request) {
        if ($request !== "admin") {
            echo "权限校验失败:无访问权限!\n";
            return;
        }
        echo "权限校验通过\n";

        // 传递给下一个处理者
        if ($this->nextHandler) {
            $this->nextHandler->handle($request);
        }
    }
}

/**
 * 具体处理者 2:数据过滤
 */
class DataFilterHandler extends Handler {
    public function handle(string $request) {
        echo "数据过滤完成\n";

        if ($this->nextHandler) {
            $this->nextHandler->handle($request);
        }
    }
}

/**
 * 具体处理者 3:日志记录
 */
class LogHandler extends Handler {
    public function handle(string $request) {
        echo "日志记录:用户 {$request} 访问了系统\n";

        if ($this->nextHandler) {
            $this->nextHandler->handle($request);
        }
    }
}

// 客户端代码:创建责任链并执行
$authHandler = new AuthHandler();
$dataFilterHandler = new DataFilterHandler();
$logHandler = new LogHandler();

// 构建责任链:权限校验 -> 数据过滤 -> 日志记录
$authHandler->setNext($dataFilterHandler)->setNext($logHandler);

// 触发请求
echo "用户 'admin' 访问:\n";
$authHandler->handle("admin");

echo "\n用户 'guest' 访问:\n";
$authHandler->handle("guest");

结果输出

用户 'admin' 访问:
权限校验通过
数据过滤完成
日志记录:用户 admin 访问了系统

用户 'guest' 访问:
权限校验失败:无访问权限!

6. 责任链模式的优缺点

✅ 优点

  • 降低耦合度:请求的发送者和处理者解耦,代码更清晰。
  • 灵活扩展:可以自由添加或移除处理者,而不影响其他代码。
  • 增强可维护性:责任链的构造可以通过配置动态调整。

❌ 缺点

  • 可能造成性能损耗:如果链条过长,可能导致大量无用的传递,影响性能。
  • 调试复杂度增加:请求经过多个处理者,可能会难以定位问题。

7. 总结

责任链模式是一种 行为设计模式,适用于 请求需要经过多个步骤处理的场景,如 权限校验、日志记录、数据过滤 等。它让代码更加模块化,可扩展性更强,同时避免了大量 if-else 判断的耦合问题。在 Laravel、Symfony 等 PHP 框架的 中间件 机制中,也能看到类似的实现方式。