职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象练成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
该模式UML结构图:
基本代码:
public abstract class Handler
{
protected Handler successor;
//设置继任者
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
//处理请求的抽象方法
public abstract void HandleRequest(int request);
}
public class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine("{0}处理请求{1}", this.GetType().Name, request);
}
else if(request!=null)
{
successor.HandleRequest(request); //转移下一位
}
}
}
public class ConcreteHanlder2 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine("{0}处理请求{1}", this.GetType().Name, request);
}
else if (request != null)
{
successor.HandleRequest(request); //转移下一位
}
}
}
public class ConcreteHandler3 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 20 && request < 30)
{
Console.WriteLine("{0}处理请求{1}", this.GetType().Name, request);
}
else if (request != null)
{
successor.HandleRequest(request); //转移下一位
}
}
}
客户端调用:
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHanlder2();
Handler h3 = new ConcreteHandler3();
h1.SetSuccessor(h2);
h2.SetSuccessor(h3); //设置上下链的关系
int[] requests = new int[] {2,5,14,22,18,3,27,20 };
foreach (var item in requests)
{
h1.HandleRequest(item);
}
Console.ReadLine();
结果:
下面请听题:
=小菜在单位,向领导请假,小于等于2天经理有权利批准,小于等于5天总监有权利批准,其他的则要交到总经理那里批准。
代码:
//申请类
public class Request
{
//申请类型 比如加薪 请假
public string RequestType { get; set; }
//申请内容
public string RequestContent { get; set; }
//天数 或钱的数量
public int Number { get; set; }
}
//管理者类
public abstract class Manager
{
protected string name;
public Manager(string name)
{
this.name = name;
}
protected Manager manager;
public void SetManager(Manager manager)
{
this.manager = manager;
}
//申请请求
public abstract void RequestApplication(Request request);
}
//经理类
public class CommonManager : Manager
{
public CommonManager(string name) : base(name) { }
public override void RequestApplication(Request request)
{
if (request.RequestType == "请假" && request.Number <= 2)
{
Console.WriteLine("{0}:{1}数量{2} 被批准", name, request.RequestContent, request.Number);
}
else if (manager !=null)
{
manager.RequestApplication(request);
}
}
}
//总监类
public class Majordomo : Manager
{
public Majordomo(string name) : base(name) { }
public override void RequestApplication(Request request)
{
if (request.RequestType == "请假" && request.Number <= 5)
{
Console.WriteLine("{0}:{1}数量{2} 被批准", name, request.RequestContent, request.Number);
}
else if(manager!=null)
{
manager.RequestApplication(request);
}
}
}
//总经理类
public class GeneralManager : Manager
{
public GeneralManager(string name) : base(name) { }
public override void RequestApplication(Request request)
{
if (request.RequestType == "请假")
{
Console.WriteLine("{0}:{1}数量{2} 被批准", name, request.RequestContent, request.Number);
}
else if (request.RequestType == "加薪" && request.Number <= 500)
{
Console.WriteLine("{0}:{1}数量{2} 被批准", name, request.RequestContent, request.Number);
}
else if (request.RequestType == "加薪" && request.Number > 500)
{
Console.WriteLine("{0}:{1}数量{2} 再说吧", name, request.RequestContent, request.Number);
}
}
}
客户端调用:
CommonManager jingli = new CommonManager("经理");
Majordomo zongjian = new Majordomo("总监");
GeneralManager zongjingli = new GeneralManager("总经理");
//设置上下级关系 经理->总监->总经理
jingli.SetManager(zongjian);
zongjian.SetManager(zongjingli);
Request request = new Request();
request.RequestType = "请假";
request.RequestContent = "小菜要请假";
request.Number = 2;
jingli.RequestApplication(request);
Request request2 = new Request();
request2.RequestType = "请假";
request2.RequestContent = "小菜要请假";
request2.Number = 5;
jingli.RequestApplication(request2);
Request request3 = new Request();
request3.RequestType = "加薪";
request3.RequestContent = "小菜要加薪";
request3.Number = 500;
jingli.RequestApplication(request3);
Request request4 = new Request();
request4.RequestType = "加薪";
request4.RequestContent = "小菜要加薪";
request4.Number = 1000;
jingli.RequestApplication(request4);
结果:
职责链模式的好处:
当客户提交一个请求时,请求是沿链传递直至有一个ConcreteHandler对象负责处理它。
这样做的好处是,请求者不用管那个对象来处理,反正该请求会被处理就对了。
接收着和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需要保持一个指向其后继者的引用,而不需要保持他所选接收者的引用。 这就大大的降低了耦合度。
四、优缺点及适用场景
优点:
1)降低了请求发送者和处理者之间的耦合。
2)把多个条件判定分散到各个处理类中,使得代码更加清晰,责任更加明确。
缺点:
1)在找到正确的处理对象之前,所有的条件判定都要执行一遍,当职责链过长时,可能会引起性能问题。
2)可能导致某个请求不被处理。
适用场景:
1)一个系统的请求需要多个对象进行审批才能完成的情况。
2)代码中有多个if-else时,也可以考虑使用职责链模式对代码进行重构。