责任链模式(Chain of Responsibility)
模式定义
责任链模式(Chain of Responsibility): 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条对象连成一条链,并沿着这条链传递请求。
UML类图
- 抽象处理者(Handler) :定义一个处理请求的接口。关联自身类型的变量。
- 具体处理者(Concrete Handler): 实现 抽象处理者中的处理方法,处理请求或者传递给下个处理对象。
- 客户端(Client):设置处理链,并调用。
代码结构
class ChainClient
{
public void Run()
{
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.ReadKey();
}
}
abstract class Handler
{
protected Handler successor;
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int request);
}
class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 0 && request < 10)
{
Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 10 && request < 20)
{
Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
class ConcreteHandler3 : Handler
{
public override void HandleRequest(int request)
{
if (request >= 20 && request < 30)
{
Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
情景案例
这里以大学中请假为例:少于2天班长处理,多于2天班长交给指导员处理,多于5天指导员交给系主任处理,多于30天不准。
class RealWorldChainClient
{
public void Run()
{
Approver h1 = new Monitor();
Approver h2 = new Instructor();
Approver h3 = new DepartmentHead();
h1.SetSuccessor(h2);
h2.SetSuccessor(h3);
int[] requests = { 2, 5, 14, 35 };
foreach (int request in requests)
{
h1.HandleRequest(request);
}
Console.ReadKey();
}
}
abstract class Approver
{
protected Approver successor;
public void SetSuccessor(Approver successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int days);
}
/// <summary>
/// 班长
/// </summary>
class Monitor : Approver
{
public override void HandleRequest(int days)
{
if (days >= 0 && days <= 2)
{
Console.WriteLine("我是班长,批准请假{0}天",days);
}
else if (successor != null)
{
successor.HandleRequest(days);
}
}
}
/// <summary>
/// 指导员
/// </summary>
class Instructor : Approver
{
public override void HandleRequest(int days)
{
if (days >= 0 && days < 10)
{
Console.WriteLine("我是指导员,批准请假{0}天", days);
}
else if (successor != null)
{
successor.HandleRequest(days);
}
}
}
/// <summary>
/// 系主任
/// </summary>
class DepartmentHead : Approver
{
public override void HandleRequest(int days)
{
if (days >= 0 && days < 30)
{
Console.WriteLine("我是指导员,批准请假{0}天", days);
}
else
{
Console.WriteLine("请假天数太多了,退学吧!");
}
}
}
自问自答
小a:你的博客好冷清呀!!!我感觉你上面讲的例子还不如用if()....else....
简单明了,整那么多类倒是增加了复杂性,感觉这个模式没必要?
LoveTomato: 啊!!!确实博客比较冷清,万事开头难吗?但开头难也要开头的吗。
回答正题 确实业务比较简单,顺序编程简单快捷。但是项目中往往是比较复杂的,比如好多网站需要用户填入的表单,后台验证数据的有效性。假设验证的指标有
- 必填性验证
- 数据类型验证(时间类型的值是否有效等)
- 业务验证(需要查询数据库)
这样每个验证都需要大段的代码,在if...else
中维护的心情你懂的,而且每次添加项新的验证都需要修改if...else
。