模式动机
职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。
链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并使请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,将请求的发送者和请求的处理者解耦。这就是职责链模式的模式动机。
模式定义
职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。由于英文翻译的不同,职责链模式又称为责任链模式,它是一种对象行为型模式。
Chain of Responsibility Pattern: Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
Frequency of use: medium low
UML图
模式结构
职责链模式包含如下角色:
Handler: 抽象处理者
ConcreteHandler: 具体处理者
Client: 客户类
模式分析
在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
请求在这条链上传递,直到链上的某一个对象处理此请求为止。
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
实例:审批假条
某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批;如果超过30天,总经理也不能审批,提示相应的拒绝信息
模式实例与解析
示例代码—加薪非要老总批?
体系结构
Manager.cs
namespace ChainofResponsibilityPattern { //管理者 abstract class Manager { protected string name; //管理者的上级 protected Manager superior; public Manager(string name) { this.name = name; } //设置管理者的上级 public void SetSuperior(Manager superior) { this.superior = superior; } //申请请求 abstract public void RequestApplications(Request request); } }
Request.cs
namespace ChainofResponsibilityPattern { class Request { //申请类别 private string requestType; public string RequestType { get { return requestType; } set { requestType = value; } } //申请内容 private string requestContent; public string RequestContent { get { return requestContent; } set { requestContent = value; } } //数量 private int number; public int Number { get { return number; } set { number = value; } } } }
CommonManager.cs
using System; namespace ChainofResponsibilityPattern { //经理 class CommonManager : Manager { public CommonManager(string name) : base(name) { } public override void RequestApplications(Request request) { if (request.RequestType == "请假" && request.Number <= 2) { //经理所能有的权限就是可批准下属两天内的假期 Console.WriteLine("{0}:{1} 数量{2} 被批准", name, request.RequestContent, request.Number); } else { if (superior != null) { superior.RequestApplications(request);//其余的申请都需转到上级 } } } } }
Majordomo.cs
using System; namespace ChainofResponsibilityPattern { //总监 class Majordomo : Manager { public Majordomo(string name) : base(name) { } public override void RequestApplications(Request request) { if (request.RequestType == "请假" && request.Number <= 5) { //总监所能有的权限就是可批准下属一周内的假期 Console.WriteLine("{0}:{1} 数量{2} 被批准", name, request.RequestContent, request.Number); } else { if (superior != null) { superior.RequestApplications(request);//其余的申请都需转到上级 } } } } }
GeneralManager.cs
using System; namespace ChainofResponsibilityPattern { //总经理 class GeneralManager : Manager { public GeneralManager(string name) : base(name) { } public override void RequestApplications(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); } } } }
Client:客户类
using System; namespace ChainofResponsibilityPattern { class Program { static void Main(string[] args) { CommonManager commonManger = new CommonManager("张经理"); Majordomo majordomo = new Majordomo("李总监"); GeneralManager generalManager = new GeneralManager("王总经理"); //设置上级,完全可以根据实际需求来更改设置 commonManger.SetSuperior(majordomo); majordomo.SetSuperior(generalManager); Request request = new Request(); request.RequestType = "请假"; request.RequestContent = "小菜请假"; request.Number = 1; //客户端的申请都是由经理发起,但实际谁来决策由具体类来处理,客户端不知道 commonManger.RequestApplications(request); Request request2 = new Request(); request2.RequestType = "请假"; request2.RequestContent = "小菜请假"; request2.Number = 4; commonManger.RequestApplications(request2); Request request3 = new Request(); request3.RequestType = "加薪"; request3.RequestContent = "小菜请求加薪"; request3.Number = 500; commonManger.RequestApplications(request3); Request request4 = new Request(); request4.RequestType = "加薪"; request4.RequestContent = "小菜请求加薪"; request4.Number = 1000; commonManger.RequestApplications(request4); Console.Read(); } } }
模式优缺点
职责链模式的优点
降低耦合度
可简化对象的相互连接
增强给对象指派职责的灵活性
增加新的请求处理类很方便
职责链模式的缺点
不能保证请求一定被接收。
系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。
模式适用环境
在以下情况下可以使用职责链模式:
有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
可动态指定一组对象处理请求。
【声明与感谢】
本文,站在许多巨人的肩膀上,借鉴和引用了许多他人拥有版权的作品或著述,在此,对前人们的贡献致谢。并同时公布引用的内容、原作者或来源(一些来源于互联网的内容本人无法追述本源,深表遗憾)。
【参考文献】
《设计模式—可复用面向对象软件的基础》作者: [美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 译者: 李英军 / 马晓星 / 蔡敏 / 刘建中 等 机械工业出版社
《重构—改善既有代码的设计》作者: Martin Fowler译者:候捷 中国电力出版社
《敏捷软件开发—原则、模式与实践》作者: Robert C. Martin 清华大学出版社
《程序员修炼之道—从小工到专家》作者: Andrew Hunt / David Thomas 电子工业出版社
《Head First 设计模式》作者: 弗里曼 译者: O'Reilly Taiwan公司 中国电力出版社
《设计模式之禅》 作者: 秦小波 机械工业出版社
MSDN WebCast 《C#面向对象设计模式纵横谈》 讲师:李建忠
刘伟. 设计模式. 北京:清华大学出版社, 2011.
刘伟. 设计模式实训教程. 北京:清华大学出版社, 2012.
《大话设计模式》 作者: 程杰 清华大学出版社
《C#图解教程》作者: 索利斯 译者: 苏林 / 朱晔 人民邮电出版社
《你必须知道的.NET》作者: 王涛
《项目中的.NET》作者: 李天平 电子工业出版社
《Microsoft .NET企业级应用架构设计》作者: (美)埃斯波西托等编著 译者: 陈黎夫
http://www.dofactory.com/Patterns/Patterns.aspx .NET Design Patterns
http://www.cnblogs.com/zhenyulu 博客作者:吕震宇
http://www.cnblogs.com/terrylee 博客作者:李会军
http://www.cnblogs.com/anlyren/ 博客作者:anlyren
http://www.cnblogs.com/idior 博客作者:idior
http://www.cnblogs.com/allenlooplee 博客作者:Allen lee
http://blog.csdn.net/ai92 博客作者:ai92
http://www.cnblogs.com/umlonline/ 博客作者:张传波
http://www.cnblogs.com/lovecherry/ 博客作者:LoveCherry