24. 职责链模式
约 1259 字大约 4 分钟
2026-03-25
定义
职责链模式(Chain ofResponsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
人话:职责链模式就像公司里的请假或加薪审批流程。员工如果想请假或者申请加薪,并不是直接找老板,而是需要 一级一级往上报,比如先找组长,再到经理,再到总监。
如果不用职责链模式来设计,程序里可能会写成一大堆判断,比如:“请假天数小于3天找组长”、“小于7天找经理”、“更长找总监”等等。这样所有逻辑都集中在一个地方,一旦审批规则变化(比如权限调整),就需要修改大量 if-else,这在软件中就属于职责耦合严重、扩展困难、代码臃肿。
而使用职责链模式之后,就相当于把“组长、经理、总监”分别看作一个个处理节点,并把它们串成一条链。每个节点只负责处理自己权限范围内的请求,如果处理不了,就把请求传递给下一个人。
这样一来:
- 组长负责处理小额度/短时间的请求
- 经理负责处理中等范围的请求
- 总监负责处理更大的请求
如果员工提交一个请求,先交给组长:
- 能处理就直接批准
- 不能处理就往上交给经理
- 经理不行再交给总监
整个过程就像“责任接力”。
在软件中也是一样:职责链模式让多个对象都有机会处理请求,请求沿着链传递,直到有一个对象处理它为止。这样就把“请求发送者”和“请求处理者”解耦,同时也让系统在新增或调整处理规则时更加灵活,不需要修改原有代码结构。
职责链模式(Chain ofResponsibility)结构图
Handler类——抽象处理者:
// Handler(抽象处理者)
abstract class Handler
{
protected Handler successor;
// 设置后继者
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
// 处理请求
public abstract void HandleRequest(int request);
}ConcreteHandler1类——具体处理者1:
// ConcreteHandler1
class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine($"{this.GetType().Name} 处理请求 {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}ConcreteHandler2类——具体处理者2:
// ConcreteHandler2
class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine($"{this.GetType().Name} 处理请求 {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}ConcreteHandler3类——具体处理者3:
// ConcreteHandler3
class ConcreteHandler3 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 20 && request < 30)
{
Console.WriteLine($"{this.GetType().Name} 处理请求 {request}");
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}客户端代码:
static void Main(string[] args)
{
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
Handler h3 = new ConcreteHandler3();
// 设置职责链
h1.SetSuccessor(h2);
h2.SetSuccessor(h3);
// 请求数组
int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
foreach (int request in requests)
{
h1.HandleRequest(request);
}
Console.Read();
}运行结果:
ConcreteHandler1 处理请求 2
ConcreteHandler1 处理请求 5
ConcreteHandler2 处理请求 14
ConcreteHandler3 处理请求 22
ConcreteHandler2 处理请求 18
ConcreteHandler1 处理请求 3
ConcreteHandler3 处理请求 27
ConcreteHandler3 处理请求 20当客户提交一个请求时,请求是沿链传递直至有一个 ConcreteHandler 对象负责处理它。
请求者不用管哪个对象来处理,反正该请求会被处理就对了。这就使得接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。这也就大大降低了耦合度了。
可以随时地增加或修改处理一个请求的结构。增强了给对象指派职责的灵活性。不过也要当心,一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理,这就很糟糕了。需要事先考虑全面。
最重要的有两点,一个是你需要事先给每个具体管理者设置他的上司是哪个类,也就是设置后继者。另一点是你需要在每个具体管理者处理请求时,做出判断,是可以处理这个请求,还是必须要“推卸责任”,转移给后继者去处理。
