概述
很多情况下,在一个软件系统中可以处理某个请求的对象不止一个,例如SCM系统中的采购单审批,主任、副董事长、董事长和董事会都可以处理采购单,他们可以构成一条处理采购单的链式结构,采购单沿着这条链进行传递,这条链就称为职责链。职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,实现请求发送者和请求处理者解耦
定义
职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。
实现
请求类
/// <summary> /// 采购申请类 /// </summary> public class PurchaseRequest { public double amount { get; set; } //采购金额 public int number { get; set; } //采购单编号 public string purpose { get; set; } //采购目的 }
请求处理者抽象类
/// <summary> /// 请求处理者 /// </summary> public abstract class Approver { /// <summary> /// 申请后续处理对象 /// </summary> protected Approver successor; /// <summary> /// 当前审批者姓名 /// </summary> protected string name; public Approver(string name) { this.name = name; } //设置后继者 public void setSuccessor(Approver successor) { this.successor = successor; } /// <summary> /// 处理采购申请的逻辑 /// </summary> /// <param name="request"></param> public abstract void processRequest(PurchaseRequest request); }
主任类
public class Director : Approver { public Director(string name) : base(name) { } public override void processRequest(PurchaseRequest request) { if (request.amount < 50000) { Console.WriteLine(string.Format("采购单:{0},金额:{1},目的:{2},由主任【{3}】审批通过。", request.number, request.amount, request.purpose, name)); } else { this.successor.processRequest(request); //转发请求 } } }
副董事长
public class VicePresident : Approver { public VicePresident(string name) : base(name) { } public override void processRequest(PurchaseRequest request) { if (request.amount < 100000) { Console.WriteLine(string.Format("采购单:{0},金额:{1},目的:{2},由副董事长【{3}】审批通过。", request.number, request.amount, request.purpose, name)); } else { this.successor.processRequest(request); //转发请求 } } }
董事长
public class President : Approver { public President(string name) : base(name) { } public override void processRequest(PurchaseRequest request) { if (request.amount < 500000) { Console.WriteLine(string.Format("采购单:{0},金额:{1},目的:{2},由董事长【{3}】审批通过。", request.number, request.amount, request.purpose, name)); } else { this.successor.processRequest(request); //转发请求 } } }
董事会
public class Congress : Approver { public Congress(string name) : base(name) { } public override void processRequest(PurchaseRequest request) { if (request.amount >= 500000) { Console.WriteLine(string.Format("采购单:{0},金额:{1},目的:{2},由【{3}】审批通过。", request.number, request.amount, request.purpose, name)); } else { this.successor.processRequest(request); //转发请求 } } }
客户端
class Program { static void Main(string[] args) { //采购申请单 PurchaseRequest request = new PurchaseRequest() { number = 1000, amount = 405000, purpose = "购买原材料经费" }; //主任 Approver director = new Director("张三"); //副董事长 Approver vicePresident = new VicePresident("李四"); director.setSuccessor(vicePresident); //董事长 Approver president = new President("王五"); vicePresident.setSuccessor(president); //董事会 Approver congress = new Congress("董事会"); president.setSuccessor(congress); director.processRequest(request); Console.ReadLine(); } }
总结
职责链模式通过建立一条链来组织请求的处理者,请求将沿着链进行传递,请求发送者无须知道请求在何时、何处以及如何被处理,实现了请求发送者与处理者的解耦。在软件开发中,如果遇到有多个对象可以处理同一请求时可以应用职责链模式,例如在Web应用开发中创建一个过滤器(Filter)链来对请求数据进行过滤,在工作流系统中实现公文的分级审批等等,使用职责链模式可以较好地解决此类问题。
主要优点
1、 职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。
2、请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。
3、在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。
4、在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。
主要缺点
1、由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理。
2、 对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
3、如果建链不当,可能会造成循环调用,将导致系统陷入死循环。