责任链模式
责任链模式(Chain of Responsibility Pattern)
定义
- 责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下一个处理者。
核心思想
-
解耦发送者和接收者:发送者不需要知道具体由哪个对象处理请求
-
动态构建处理链:可以灵活地调整或扩展处理流程
-
多处理机会:请求可以被链中的多个对象处理,也可以不被处理
模式结构
Handler(抽象处理者)
│
├── ConcreteHandlerA(具体处理者A)
├── ConcreteHandlerB(具体处理者B)
└── ConcreteHandlerC(具体处理者C)
关键组件:
-
Handler:定义处理请求的接口,通常包含设置后继者的方法
-
ConcreteHandler:具体处理者,处理其负责的请求,否则将请求转发给后继者
-
Client:向链上的具体处理者对象提交请求
主要解决的问题
-
请求发送者与接收者耦合:避免请求发送者与特定接收者绑定
-
动态指定请求处理者:运行时可以动态改变处理请求的对象
-
多级处理需求:当需要多个对象都有机会处理请求时
代码示例
- 场景描述
实现一个采购审批系统,不同级别的管理者有不同的审批权限:
经理:可审批金额 ≤ 5000
总监:可审批金额 ≤ 10000
CEO:可审批金额 ≤ 50000
using System;
// 采购请求
public class PurchaseRequest
{
public decimal Amount { get; set; }
public string Purpose { get; set; }
public PurchaseRequest(decimal amount, string purpose)
{
Amount = amount;
Purpose = purpose;
}
}
// 抽象处理者
public abstract class Approver
{
protected Approver Successor { get; private set; }
protected string Name { get; }
protected Approver(string name)
{
Name = name;
}
public void SetSuccessor(Approver successor)
{
this.Successor = successor;
}
public abstract void ProcessRequest(PurchaseRequest request);
}
// 具体处理者 - 经理
public class Manager : Approver
{
public Manager(string name) : base(name) {}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount <= 5000)
{
Console.WriteLine($"经理 {Name} 审批了采购请求:金额 {request.Amount},用途 {request.Purpose}");
}
else if (Successor != null)
{
Successor.ProcessRequest(request);
}
}
}
// 具体处理者 - 总监
public class Director : Approver
{
public Director(string name) : base(name) {}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount <= 10000)
{
Console.WriteLine($"总监 {Name} 审批了采购请求:金额 {request.Amount},用途 {request.Purpose}");
}
else if (Successor != null)
{
Successor.ProcessRequest(request);
}
}
}
// 具体处理者 - CEO
public class CEO : Approver
{
public CEO(string name) : base(name) {}
public override void ProcessRequest(PurchaseRequest request)
{
if (request.Amount <= 50000)
{
Console.WriteLine($"CEO {Name} 审批了采购请求:金额 {request.Amount},用途 {request.Purpose}");
}
else
{
Console.WriteLine($"金额过大({request.Amount}),需要董事会讨论!");
}
}
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
// 创建处理者
var manager = new Manager("张经理");
var director = new Director("李总监");
var ceo = new CEO("王CEO");
// 构建责任链
manager.SetSuccessor(director);
director.SetSuccessor(ceo);
// 创建不同金额的采购请求
var requests = new[]
{
new PurchaseRequest(4000, "购买办公用品"),
new PurchaseRequest(8000, "团队建设活动"),
new PurchaseRequest(30000, "新服务器采购"),
new PurchaseRequest(100000, "新建办公楼")
};
// 处理请求
foreach (var request in requests)
{
manager.ProcessRequest(request);
}
/* 输出:
经理 张经理 审批了采购请求:金额 4000,用途 购买办公用品
总监 李总监 审批了采购请求:金额 8000,用途 团队建设活动
CEO 王CEO 审批了采购请求:金额 30000,用途 新服务器采购
金额过大(100000),需要董事会讨论!
*/
}
}
总结
优点
-
降低耦合度:请求发送者无需知道具体处理者
-
增强灵活性:可以动态地重新组织链或新增处理者
-
明确责任划分:每个处理者只需关注自己责任范围内的请求
-
符合开闭原则:新增处理者无需修改现有代码
缺点
-
请求可能未被处理:没有明确的接收者保证
-
性能影响:较长的责任链可能影响性能
-
调试困难:请求的传递过程可能比较复杂
适用场景
-
有多个对象可以处理同一个请求,但具体由哪个对象处理在运行时自动确定
-
想在不明确指定接收者的情况下向多个对象中的一个提交请求
-
需要动态指定一组对象处理请求
责任链模式在审批流程、异常处理、事件处理等场景中非常有用。