初识设计模式——职责链模式(Chain of Responsibility Pattern)

cuixiaogang

职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许将请求沿着处理者链进行发送。收到请求后,每个处理者可以选择处理请求,或者将请求传递给链上的下一个处理者。这种模式将请求的发送者和接收者解耦,使得系统中的多个对象都有机会处理该请求,而不必明确指定请求的接收者。

简单来说:职责链模式将多个对象连成一条链,并沿着这条链传递请求,使得链上的对象都有机会处理请求,从而避免请求的发送者和接收者之前的耦合关系。

示例

场景

以 Laravel 框架为例,它的中间件就是按照职责链模式来实现的。

  1. 客户端发起的请求首先会到达第一个中间件(权限中间件)。
  2. 权限中间件会验证请求的合法性,若请求的合法性校验通过,则将请求传递给下一个中间件(日志中间件);若合法性校验不通过,则直接返回错误响应。
  3. 日志中间件会记录请求日志,并实现本地化(日志机)存储,处理完成后,将请求传递给下一个中间件(后置处理中间件)。
  4. 后置处理中间件在请求过程中不会做任何操作,会直接将请求发送给控制器,进行最终的业务处理。后置处理中间件在响应阶段,会根据请求的方法名,处理不同的业务逻辑,并且将响应数据进行返回。
  5. 职责链的最后一个节点,用来处理相关的业务逻辑。

代码

  • 权限中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class PermissionMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// 模拟权限验证,这里假设请求中包含 'valid' 参数且值为 true 时验证通过
if ($request->input('valid', false) === true) {
return $next($request);
}

return response('Permission denied', 403);
}
}
  • 日志中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\Log;

class LoggingMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// 记录请求日志
Log::info('Request received: '. $request->fullUrl());

return $next($request);
}
}
  • 后置处理中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class PostProcessingMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);

// 根据请求方法名处理不同的业务逻辑
switch ($request->method()) {
case 'GET':
// 处理 GET 请求的业务逻辑
break;
case 'POST':
// 处理 POST 请求的业务逻辑
break;
// 可以添加更多的请求方法处理逻辑
}

return $response;
}
}
  • 注册中间件

app/Http/Kernel.php中注册中间件

1
2
3
4
5
protected $routeMiddleware = [
'permission' => \App\Http\Middleware\PermissionMiddleware::class,
'logging' => \App\Http\Middleware\LoggingMiddleware::class,
'postprocessing' => \App\Http\Middleware\PostProcessingMiddleware::class,
];
  • 控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ExampleController extends Controller
{
public function handleRequest(Request $request)
{
// 处理业务逻辑
return response('Business logic processed successfully', 200);
}
}

总结

通过以上步骤,我们就实现了一个基于 Laravel 框架的职责链模式。客户端发起的请求会依次经过权限中间件、日志中间件和后置处理中间件,最终到达控制器进行业务处理。后置处理中间件会在响应阶段根据请求方法名处理不同的业务逻辑。

职责链模式的优缺点

优点

  • 解耦责任与请求:发送者无需知道具体哪个处理者会处理请求,只需将请求发送到链上,处理者之间也只需知道下一个处理者的引用。这种解耦提高了系统的灵活性和可维护性。
  • 动态灵活的责任分配:可以在运行时动态添加、修改或删除处理者,也可以动态调整处理链的顺序,符合开闭原则(对扩展开放,对修改关闭)。
  • 单一职责原则:每个处理者专注于自己的职责(如权限验证、日志记录等),符合单一职责原则,代码结构更清晰,可读性更强。
  • 简化对象间的连接:处理者只需持有下一个处理者的引用,无需了解整个链的结构,降低了对象间的耦合度。
  • 支持多处理者协作:请求可以被多个处理者依次处理(如先验证权限,再记录日志),适合需要流程化处理的场景(如中间件、工作流引擎)。

缺点

  • 请求处理可能存在延迟:若处理链较长,或处理者需要多次判断是否属于自己的职责,可能导致请求处理时间增加,影响性能(尤其是同步处理场景)。
  • 调试难度较高:由于请求的处理路径是动态的,且可能经过多个处理者,排查问题时需要跟踪整个链,增加了调试成本。
  • 可能出现无人处理的情况:若链中所有处理者都不处理请求,且没有设置默认处理者(如链末端的 “兜底” 处理者),可能导致请求丢失或错误。
  • 处理顺序依赖链结构:处理者的顺序对请求的处理结果可能有直接影响(如权限验证必须在业务处理之前),需要严格确保链的顺序正确,否则可能导致逻辑错误。
  • 职责划分不明确时的混乱:若处理者的职责边界模糊,可能导致多个处理者重复处理请求,或推诿责任,破坏模式的设计初衷。

职责链模式的适用场景

  • 流程化处理:如中间件(如 Laravel 的中间件链)、过滤器链、审批流程(逐层审批)。
  • 需要动态调整处理逻辑:如日志处理(不同级别日志由不同处理器处理)、错误处理(逐级向上抛出)。
  • 解耦请求发送与处理:发送者不关心具体处理者,只需确保请求被处理。
On this page
初识设计模式——职责链模式(Chain of Responsibility Pattern)