责任链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式
纯的责任链模式:
- 一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后
又将责任向下传递的情况 - 一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况
不纯的责任链模式:
- 允许某个请求被一个具体处理者部分处理后再向下传递
- 或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求
- 而且一个请求可以最终不被任何处理者对象所接收
适用场景
-
有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的
-
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
-
可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序
职责链模式的主要优点
-
对象仅需知道该请求会被处理即可,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度
-
请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接
-
在给对象分派职责时,职责链可以给我们更多的灵活性,可以在运行时对该链进行动态的增删改,改变处理一个请求的职责
-
新增一个新的具体请求处理者时无须修改原有代码,只需要在客户端重新建链即可,符合 "开闭原则"
举一个例子 :比如我们平时上班的时候想有事情想请假,需要通过层层的审批,当然如果天数较少那么通常只需要你直系上司通过就好了,若是请假天数较多,那么需要通过好几层的审批才会通过。如果我们将这一个行为用程序来表达,那么首先会想到的就是写一个Process方法,它代表请假这一行为,然后再到里面做各种处理,方法内部写if(经理通过并且天数小于2天)elseif(CTO通过天数小于3天)elseif(老板通过天数小于4天)等等这样做不是不可以,但是这样做的弊端就是:
- 假设领导很多导致该方法过于庞大,而且违背了单一职责原则
- 如果想要修改请假流程,那么必须修改这个类的源码,违背了开闭原则
- 而且流程是由源码写死了,客户端不能根据具体需求自定义流程
public boolean process(String request, int number)
{
boolean result = handleByDirector(request); // 主管处理
if (result == false)
{ // 主管不批准
return false;
}
else if (number < 3)
{ // 主管批准且天数小于 3
return true;
}
result = handleByManager(request); // 准管批准且天数大于等于 3,提交给经理处理
if (result == false)
{ // 经理不批准
return false;
}
else if (number < 7)
{ // 经理批准且天数小于 7
return true;
}
result = handleByTopManager(request); // 经理批准且天数大于等于 7,提交给总经理处理
if (result == false)
{ // 总经理不批准
return false;
}
return true; // 总经理最后批准
}
public boolean handleByDirector(String request)
{
// 主管处理该请假申请
}
public boolean handleByManager(String request)
{
// 经理处理该请假申请
}
public boolean handleByTopManager(String request)
{
// 总经理处理该请假申请
}
引入职责链模式(不纯)的代码:
public class Request
{
private int requestNum;
public int RequestNum
{
get
{
return requestNum;
}
set
{
requestNum = value;
}
}
public Request(int requestNum)
{
this.RequestNum = requestNum;
}
}
public abstract class Leader
{
public virtual void HanleRequest(Request request)
{
if(next != null)
{
next.HanleRequest(request);
}
else
{
Console.WriteLine("请假天数太多未通过");
}
}
private Leader next;
public Leader(Leader leader)
{
next = leader;
}
protected abstract bool SlefIsCanHanle(Request request);
}
//经理类 最多请假2天
public class Manager : Leader
{
public Manager(Leader leader) : base(leader)
{
}
protected override bool SlefIsCanHanle(Request request)
{
return request.RequestNum <= 2;
}
public override void HanleRequest(Request request)
{
if (SlefIsCanHanle(request))
{
Console.WriteLine("经理请假通过");
}
else
{
base.HanleRequest(request);
}
}
}
//CTO可以审批请假3天
public class CTO : Leader
{
public CTO(Leader leader) : base(leader)
{
}
protected override bool SlefIsCanHanle(Request request)
{
return request.RequestNum <= 3;
}
public override void HanleRequest(Request request)
{
if (SlefIsCanHanle(request))
{
Console.WriteLine("CTO请假通过");
}
else
{
base.HanleRequest(request);
}
}
}
客户端调用:
//责任链模式
Request request = new Request(3);
Leader cto = new CTO(null);
Leader manager = new Manager(cto);
manager.HanleRequest(request);
在调用的时候我们可以自己决定下一个流程处理的对象是谁。