责任链模式

发布时间 2023-06-06 16:13:25作者: 一只向上爬的小蜗牛

一、定义

多个对象都有机会处理某个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

二、UML类图

 

  • Handler:抽象处理者角色,是一个处理请求的接口或抽象类;

  • ConcreteHandler:具体的处理者角色,具体的处理者接收到请求后可以选择将请求处理掉,或者将请求传递给下一个处理者。

  • ConcreteStrategy:具体的策略实现。

三、示例

用程序实现一个请假流程,根据请假天数不同,需要各级领导审批,例如,如果请假时长不超过1天,则直接团队负责人申请即可,超过1天不超过3天则需要项目经理审批通过才行,而超过3天不超过7天则需要CTO审批等等。

代码

 1.Manager.cs

 public abstract class Manager
    {
        public Manager NextManager { get; set; }

        public string Name { get; set; }

        public Manager(string name)
        {
            Name = name;
        }

        public void HandleRequest(LeaveContext context)
        {
            if (CanHandle(context))
            {
                Handle(context);
                return;
            }

            NextManager?.HandleRequest(context);
        }

        protected abstract bool CanHandle(LeaveContext context);

        protected abstract void Handle(LeaveContext context);
    }

2.TL.cs

    /// <summary>
    /// 团队领导者
    /// </summary>
    public class TL : Manager
    {
        public TL(string name): base(name)
        {
        }

        protected override bool CanHandle(LeaveContext context)
        {
            return context.Request.LeaveDays <= 1;
        }

        protected override void Handle(LeaveContext context)
        {
            context.Response = new LeaveResponse
            {
                Approver = "TL:" + Name,
                IsAgreed = true
            };
        }
    }

3.PM.cs

    /// <summary>
    /// 项目经理
    /// </summary>
    public class PM : Manager
    {
        public PM(string name): base(name)
        {
        }

        protected override bool CanHandle(LeaveContext context)
        {
            return context.Request.LeaveDays > 1
                && context.Request.LeaveDays <= 3;
        }

        protected override void Handle(LeaveContext context)
        {
            context.Response = new LeaveResponse
            {
                Approver = "PM:" + Name,
                IsAgreed = true
            };
        }
    }

4.HR.cs

 public class HR
    {
        private List<Manager> _managers = new List<Manager>();

        public void AddManager(Manager manager)
        {
            _managers.Add(manager);
        }

        public Manager GetManager()
        {
            Manager currentManager = null;
            for (int i = _managers.Count - 1; i >= 0; i--)
            {
                if (currentManager != null)
                {
                    _managers[i].NextManager = currentManager;
                }

                currentManager = _managers[i];
            }

            return currentManager;
        }
    }

5.LeaveContext.cs

    /// <summary>
    /// 请假单
    /// </summary>
    public class LeaveContext
    {
        /// <summary>
        /// 申请
        /// </summary>
        public LeaveRequest Request { get; set; }

        /// <summary>
        /// 审批结果
        /// </summary>
        public LeaveResponse Response { get; set; }
    }

6.LeaveRequest.cs

    /// <summary>
    /// 请假申请
    /// </summary>
    public class LeaveRequest
    {
        /// <summary>
        /// 申请人
        /// </summary>
        public string Applicant { get; set; }

        /// <summary>
        /// 请假天数
        /// </summary>
        public int LeaveDays { get; set; }

        /// <summary>
        /// 请假理由
        /// </summary>
        public string Reason { get; set; }
    }

7.LeaveResponse.cs

    /// <summary>
    /// 审批结果
    /// </summary>
    public class LeaveResponse
    {
        /// <summary>
        /// 审批人
        /// </summary>
        public string Approver { get; set; }

        /// <summary>
        /// 是否同意
        /// </summary>
        public bool IsAgreed { get; set; }
    }

8.Program.cs

internal class Program
    {
        static void Main(string[] args)
        {
            LeaveContext context = new LeaveContext
            {
                Request = new LeaveRequest
                {
                    Applicant = "张三",
                    Reason = "世界那么大,我想去看看",
                    LeaveDays = 2
                }
            };

            HR hR = new HR();
            hR.AddManager(new TL("李四"));
            hR.AddManager(new PM("王五"));
            hR.AddManager(new CTO("赵六"));

            Manager manager = hR.GetManager();
            manager.HandleRequest(context);
            if (context.Response == null)
            {
                Console.WriteLine($"{context.Request.LeaveDays}天假期太长,没人处理请假申请,请假失败");
            }
            else
            {
                Console.WriteLine($"{context.Response.Approver}审批了{context.Request.Applicant}的{context.Request.LeaveDays}天请假申请,请假事由{context.Request.Reason}");
            }
        }
    }

运行结果:

 

四、优缺点

优点

  1. 请求和处理分离,请求者可以不用知道是谁处理的,处理者可以不用知道请求的全貌,两者解耦,提高系统的灵活性。

缺点

  1. 性能不高;
  2. 调试不很方便。