赞
踩
在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假或者加薪,可处理的领导有HR、部门负责人、副总经理、总经理等,但每个领导能批准的天数和加薪额度不同,员工必须根据自己的情况去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏、发薪资等。
又名责任链模式,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
职责链模式主要包含以下角色:
现需要开发一个请假流程控制系统。请假一天以下的假只需要主管同意即可;请假2天需要项目经理同意;请假2天到4天的假还需要部门经理同意;请求4天到15天还需要总经理同意才行。
/// <summary> /// Program /// </summary> Application application = new Application() { Code = "Leave001", Description = "请假单20220715", Num = 16, Type = "请假单", IsApproval = false, }; #region 面向过程编程POP { if (application.Num <= 8) { Console.WriteLine("主管批准"); } else if (application.Num <= 16) { Console.WriteLine("项目经理批准"); } else if (application.Num <= 32) { Console.WriteLine("部门经理批准"); } else { Console.WriteLine("总经理批准"); } } #endregion
如果你的编程思想还是面向过程编程(POP)的思想,那么可能会写出上述代码。
但是我们要发挥C#面向对象编程(OOP)的特点,所以我们可以分别创建主管、项目经理、部门经理、总经理类,并在这些类中进行判断和流转。
首先,我们创建各个管理者类;
/// <summary> /// 主管 /// </summary> public class Director { public string Name { get; set; } public void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 8) { Console.WriteLine("主管审批通过!"); application.IsApproval = true; } } } /// <summary> /// 项目经理 /// </summary> public class ProjectManager { public string Name { get; set; } public void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 16) { Console.WriteLine("项目经理通过"); application.IsApproval = true; } } } /// <summary> /// 部门经理 /// </summary> public class DivisionManager { public string Name { get; set; } public void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 32) { Console.WriteLine("部门经理审批通过"); application.IsApproval = true; } } } /// <summary> /// 总经理 /// </summary> public class President { public string Name { get; set; } public override void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); Console.WriteLine("总经理审批通过"); application.IsApproval = true; } }
并通过Program类进行流转,
/// <summary> /// Program /// </summary> #region 面向对象编程OOP { Director director = new Director(); director.Name = "Tom"; director.Approval(application); if (!application.IsApproval) { ProjectManager projectManager = new ProjectManager(); projectManager.Name = "Bob"; projectManager.Approval(application); if (!application.IsApproval) { DivisionManager divisionManager = new DivisionManager(); divisionManager.Name = "Mark"; divisionManager.Approval(application); if (!application.IsApproval) { President president = new President(); president.Name = "Alice"; president.Approval(application); } } } } #endregion =============================================== Director-Tom Approval ProjectManager-Bob Approval DivisionManager-Mark Approval 部门经理审批通过
但是,这么写就把业务都暴露在了主方法内,我们需要把流转放入管理者类内部,使其自动流转。我们对各个管理者类修改如下,
/// <summary> /// 主管 /// </summary> public class Director { public string Name { get; set; } public void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 8) { Console.WriteLine("主管审批通过!"); application.IsApproval = true; } else { Console.WriteLine("我没有权限,请找上级审批!"); ProjectManager manager = new ProjectManager(); manager.Approval(application); } } } /// <summary> /// 项目经理 /// </summary> public class ProjectManager { public string Name { get; set; } public void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 16) { Console.WriteLine("项目经理通过"); application.IsApproval = true; } else { Console.WriteLine("我没有权限,请找上级审批!"); DivisionManager manager = new DivisionManager(); manager.Approval(application); } } } /// <summary> /// 部门经理 /// </summary> public class DivisionManager { public string Name { get; set; } public void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 32) { Console.WriteLine("部门经理审批通过"); application.IsApproval = true; } else { Console.WriteLine("我没有权限,请找上级审批!"); President manager = new President(); manager.Approval(application); } } }
此时,Program类内部只需要如下代码,
/// <summary> /// Program /// </summary> #region 审批自动流转 { Director director = new Director(); director.Name = "Tom"; director.Approval(application); } #endregion ===================================== Director-我是主管 Approval 我没有权限,请找上级审批! ProjectManager- Approval 我没有权限,请找上级审批! DivisionManager- Approval 部门经理审批通过
我们可以看出各个管理者类有着很多重复的代码,此时我们就可以把重复的代码抽离出来,放到一个抽象类里面。
/// <summary> /// 抽象管理者类 /// </summary> public abstract class AbstractManager { public string Name { get;set;} public abstract void Approval(Application application); } /// <summary> /// 主管 /// </summary> public class Director : AbstractManager { public override void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 8) { Console.WriteLine("主管审批通过!"); application.IsApproval = true; } else { Console.WriteLine("我没有权限,请找上级审批!"); ProjectManager manager = new ProjectManager(); manager.Approval(application); } } } ......
进一步地,当我们要在项目经理和部门经理类直接加一个流转,或者要把项目经理的流转放在主管前面时,我们就需要去修改各个管理者类的代码,这也就违背了开闭原则。所以,我们这里要使得流转的过程能够控制,另一位开发同事可以自主去修改流转。具体代码如下,
public abstract class AbstractManager { public string Name { get;set;} protected AbstractManager _abstractManager = null; public void SetNext(AbstractManager abstractManager) { this._abstractManager = abstractManager; } public abstract void Approval(Application application); protected void ApprovalNext(Application application) { Console.WriteLine("我没有权限,请找上级审批!"); if (this._abstractManager != null) { this._abstractManager.Approval(application); } } } /// <summary> /// 主管 /// </summary> public class Director : AbstractManager { public override void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 8) { Console.WriteLine("主管审批通过!"); application.IsApproval = true; } else { base.ApprovalNext(application); } } } /// <summary> /// 项目经理 /// </summary> public class ProjectManager : AbstractManager { public override void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 16) { Console.WriteLine("项目经理通过"); application.IsApproval = true; } else { base.ApprovalNext(application); } } } /// <summary> /// 部门经理 /// </summary> public class DivisionManager:AbstractManager { public override void Approval(Application application) { Console.WriteLine($"{this.GetType().Name}-{this.Name} {nameof(Approval)}"); if (application.Num < 32) { Console.WriteLine("部门经理审批通过"); application.IsApproval = true; } else { base.ApprovalNext(application); } } } /// <summary> /// Program /// </summary> #region 审批流程变化(责任链模式精髓) { AbstractManager manager1 = new Director(); manager1.Name = "Tom"; AbstractManager manager2 = new ProjectManager(); manager2.Name = "Bob"; AbstractManager manager3 = new DivisionManager(); manager3.Name = "Mark"; AbstractManager manager4 = new President(); manager4.Name = "Alice"; manager1.SetNext(manager3); manager3.SetNext(manager4); manager1.Approval(application); } #endregion ============================================================== Director-Tom Approval 我没有权限,请找上级审批! DivisionManager-Mark Approval 部门经理审批通过
上述Program部分代码可以看出,我们能够将主管的流转改为部门经理。如果我们想要在项目经理之后加上大项目经理,我们也主要添加一个大项目经理类,然后在配置项目经理SetNext流转到大项目经理,不用去修改其他管理者类。
当然,我们如果不希望把业务流转的过程暴露在Program类中,我们可以引入建造者模型,在一个builder类中专门创建管理者类,并管理他们的流转方式。
public class ManagerBuilder { public static AbstractManager Build() { AbstractManager manager1 = new Director(); manager1.Name = "Tom"; AbstractManager manager2 = new ProjectManager(); manager2.Name = "Bob"; AbstractManager manager3 = new DivisionManager(); manager3.Name = "Mark"; AbstractManager manager4 = new President(); manager4.Name = "Alice"; manager1.SetNext(manager3); manager3.SetNext(manager4); return manager1; } } /// <summary> /// Program /// </summary> #region 责任链模式+建造者模式 { AbstractManager manager = ManagerBuilder.Build(); manager.Approval(application); } #endregion ============================================================== Director-Tom Approval 我没有权限,请找上级审批! DivisionManager-Mark Approval 部门经理审批通过
降低了对象之间的耦合度
该模式降低了请求发送者和接收者的耦合度。
增强了系统的可扩展性
可以根据需要增加新的请求处理类,满足开闭原则。
增强了给对象指派职责的灵活性
当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。
责任链简化了对象之间的连接
一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
责任分担
每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。