一、背景
现实中,请假的OA申请,请假天数如果是半天到1天,可能直接主管批准即可;如果是1到3天的假期,需要部门经理批准;如果是3天到30天,则需要总经理审批;大于30天,正常不会批准。
在计算机软硬件中也有相关例子,如总线网中数据报传送,每台计算机根据目标地址是否同自己的地址相同来决定是否接收;还有异常处理中,处理程序根据异常的类型决定自己是否处理该异常
二、定义
责任链(Chain of Responsibility Pattern),顾名思义,就是用来处理相关事务责任的一条执行链,执行链上有多个节点,每个节点都有机会(条件匹配)处理请求事务,如果某个节点处理完了就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。
2.1 模式的结构
职责链模式主要包含以下角色。
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。
其结构图如图 1 所示。客户端可按图 2 所示设置责任链
2.2 代码
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
/// <summary>
/// 抽象处理者角色
/// </summary>
abstract class Handler
{
private Handler next;
public void setNext(Handler next)
{
this.next = next;
}
public Handler getNext()
{
return next;
}
//处理请求的方法
public abstract void handleRequest(String request);
}
/// <summary>
/// 具体处理者角色1
/// </summary>
class ConcreteHandler1 : Handler
{
public override void handleRequest(String request)
{
if (request.Equals("one"))
{
Console.WriteLine("具体处理者1负责处理该请求!");
}
else
{
if (getNext() != null)
{
getNext().handleRequest(request);
}
else
{
Console.WriteLine("没有人处理该请求!");
}
}
}
}
/// <summary>
/// 具体处理者角色2
/// </summary>
class ConcreteHandler2 : Handler
{
public override void handleRequest(String request)
{
if (request.Equals("two"))
{
Console.WriteLine("具体处理者2负责处理该请求!");
}
else
{
if (getNext() != null)
{
getNext().handleRequest(request);
}
else
{
Console.WriteLine("没有人处理该请求!");
}
}
}
}
class Program
{
static void Main(string[] args)
{
//组装责任链
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
//提交请求
handler1.handleRequest("two");
Console.ReadKey();
}
}
}
运行结果
三、实践
用责任链模式设计一个请假条审批模块。
分析:假如规定学生请假小于或等于 2 天,班主任可以批准;小于或等于 7 天,系主任可以批准;小于或等于 10 天,院长可以批准;其他情况不予批准;这个实例适合使用职责链模式实现。
结构图如下:
代码
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
/// <summary>
/// 抽象处理者:领导类
/// </summary>
public abstract class Leader
{
protected int Level1 = 2;
protected int Level12 = 7;
protected int Level13 = 10;
protected int Level14 = 20;
private Leader next;
public void setNext(Leader next)
{
this.next = next;
}
public Leader getNext()
{
return next;
}
/// <summary>
/// 处理请求的方法
/// </summary>
/// <param name="LeaveDays"></param>
public abstract void handleRequest(int LeaveDays);
}
/// <summary>
/// 具体处理者1:班主任类
/// </summary>
public class ClassAdviser : Leader
{
public override void handleRequest(int LeaveDays)
{
if (LeaveDays <= Level1)
{
Console.WriteLine("班主任批准您请假" + LeaveDays + "天。");
}
else
{
if (getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
Console.WriteLine("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者2:系主任类
public class DepartmentHead : Leader
{
public override void handleRequest(int LeaveDays)
{
if (LeaveDays <= Level12)
{
Console.WriteLine("系主任批准您请假" + LeaveDays + "天。");
}
else
{
if (getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
Console.WriteLine("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者3:院长类
public class Dean : Leader
{
public override void handleRequest(int LeaveDays)
{
if (LeaveDays <= Level13)
{
Console.WriteLine("院长批准您请假" + LeaveDays + "天。");
}
else
{
if (getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
Console.WriteLine("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者4:教务处长类
public class DeanOfStudies : Leader
{
public override void handleRequest(int LeaveDays)
{
if (LeaveDays <= 20)
{
Console.WriteLine("教务处长批准您请假" + LeaveDays + "天。");
}
else
{
if (getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
Console.WriteLine("请假天数太多,没有人批准该假条!");
}
}
}
}
class Program
{
static void Main(string[] args)
{
//组装责任链
Leader teacher1 = new ClassAdviser();
Leader teacher2 = new DepartmentHead();
Leader teacher3 = new Dean();
//Leader teacher4=new DeanOfStudies();
teacher1.setNext(teacher2);
teacher2.setNext(teacher3);
//teacher3.setNext(teacher4);
//提交请求
teacher1.handleRequest(8);
Console.ReadKey();
}
}
}
四、总结
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。
使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。
参考:
http://c.biancheng.net/view/1383.html
https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html