欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式-职责链模式(ChainOfResponsibility)

程序员文章站 2022-12-20 23:33:53
讲故事 书接上文, "状态模式" 完美解决了多判断分支分支问题,符合了我 "人生信条" 的第一、第三条。今天来探讨一下状态模式异父异母的亲兄弟 职责链模式 ,它们都有异曲同工之妙,实际开发中可根据口味,自行选用。 今天的故事背景就放在我们平时 申请加薪、请假等活动中,我们都知道,随着我们申请内容的不 ......

讲故事

书接上文,完美解决了多判断分支分支问题,符合了我的第一、第三条。今天来探讨一下状态模式异父异母的亲兄弟职责链模式,它们都有异曲同工之妙,实际开发中可根据口味,自行选用。

今天的故事背景就放在我们平时 申请加薪、请假等活动中,我们都知道,随着我们申请内容的不同,审批人员的等级也不同。我们就先用最简单的代码模拟一下

coding

requesttype枚举,规范我们申请的类型

    /// <summary>
    /// 请求类型
    /// </summary>
    public enum requesttype
    {
        /// <summary>
        /// 请假
        /// </summary>
        leave,

        /// <summary>
        /// 加薪
        /// </summary>
        payrise
    }

requset类,简单描述申请内容

    /// <summary>
    /// 请求
    /// </summary>
    public class requset
    {
        /// <summary>
        /// 请求类型
        /// </summary>
        public requesttype type { get; set; }

        /// <summary>
        /// 请求数量
        /// </summary>
        public int number { get; set; }

        /// <summary>
        /// 请求说明
        /// </summary>
        public string content
        {
            get
            {
                switch (type)
                {
                    case requesttype.leave:
                        return $"请假{number}天";

                    case requesttype.payrise:
                        return $"加薪{number}元";

                    default:
                        return "未知";
                }
            }
        }
    }

managertype枚举,定义不同的审批人员类型

    /// <summary>
    /// 管理者类型
    /// </summary>
    public enum managertype
    {
        pm,
        cto,
        ceo
    }

manager类,审批人员,处理我们的请求

    public class manager
    {
        private readonly managertype _managertype;

        public manager(managertype managertype)
        {
            _managertype = managertype;
        }

        /// <summary>
        /// 处理请求
        /// </summary>
        public void process(requset requset)
        {
            if (_managertype == managertype.pm)
            {
                if (requset.type == requesttype.leave && requset.number <= 2)
                {
                    console.writeline($"项目经理 已批准 你的 {requset.content} 申请");
                }
                else
                {
                    console.writeline($"项目经理 无权批准 你的 {requset.content} 申请");
                }
            }
            else if (_managertype == managertype.cto)
            {
                if (requset.type == requesttype.leave)
                {
                    if (requset.number <= 5)
                    {
                        console.writeline($"cto 已批准 你的 {requset.content} 申请");
                    }
                    else
                    {
                        console.writeline($"cto 无权批准 你的 {requset.content} 申请");
                    }
                }
                else
                {
                    if (requset.number <= 500)
                    {
                        console.writeline($"cto 已批准 你的 {requset.content} 申请");
                    }
                    else
                    {
                        console.writeline($"cto 无权批准 你的 {requset.content} 申请");
                    }
                }
            }
            else if (_managertype == managertype.ceo)
            {
                if (requset.type == requesttype.leave)
                {
                    console.writeline($"ceo 已批准 你的 {requset.content} 申请");
                }
                else
                {
                    if (requset.number <= 1000)
                    {
                        console.writeline($"ceo 已批准 你的 {requset.content} 申请");
                    }
                    else
                    {
                        console.writeline($"ceo对你的 {requset.content} 申请 说:“小子,你有点飘啊!”");
                    }
                }
            }
        }
    }

客户端

    internal class program
    {
        private static void main(string[] args)
        {
            //创建领导
            var pm = new manager(managertype.pm);
            var cto = new manager(managertype.cto);
            var ceo = new manager(managertype.ceo);

            //创建 请假请求
            var request1 = new requset
            {
                type = requesttype.leave,
                number = 5
            };

            pm.process(request1);
            cto.process(request1);
            ceo.process(request1);
            console.writeline("\n");

            //创建 加薪请求
            var request2 = new requset
            {
                type = requesttype.payrise,
                number = 2000
            };
            pm.process(request2);
            cto.process(request2);
            ceo.process(request2);

            console.writeline("\nhappy ending~");
            console.readline();
        }
    }

结果展示:

项目经理 无权批准 你的 请假5天 申请
cto 已批准 你的 请假5天 申请
ceo 已批准 你的 请假5天 申请


项目经理 无权批准 你的 加薪2000元 申请
cto 无权批准 你的 加薪2000元 申请
ceo对你的 加薪2000元 申请 说:“小子,你有点飘啊!”

我们code review后,就会发现manager.process()又丑又长呀,同样是出现的三个问题:方法长,分支多,难维护。

那我们怎么使用职责链模式来解决呢?我们先来了解一下它...

职责链模式

敲黑板·划重点

定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一个链,并沿着这条链传递请求,知道有一个对象处理请求为止。

好处: 接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需要保持它所有的候选接受者的引用。【降低耦合度】

注意: 一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理,需要考虑全面!

在下面代码优化中来深化对定义、好处的理解吧

code upgrade

manager抽象类,不同权限审批人员的基类,可以设置下一级审批人员,形成一条职责链

    public abstract class manager
    {
        protected readonly managertype _managertype;
        
        /// <summary>
        /// 下一个处理者
        /// </summary>
        protected manager successor { get; private set; }

        public manager(managertype managertype)
        {
            _managertype = managertype;
        }

        /// <summary>
        /// 设置下一个处理者
        /// </summary>
        /// <param name="manager"></param>
        public void setsuccessor(manager manager)
        {
            successor = manager;
        }

        /// <summary>
        /// 处理请求
        /// </summary>
        /// <param name="requset"></param>
        public abstract void process(requset requset);
    }

pmctoceo类,具体的审批人,实现处理方法process()

    public class pm : manager
    {
        public pm(managertype managertype) : base(managertype)
        {
        }

        public override void process(requset requset)
        {
            if (requset.type == requesttype.leave && requset.number <= 2)
            {
                console.writeline($"项目经理 已批准 你的 {requset.content} 申请");
                return;
            }

            if (successor != null)
            {
                //交由下一级处理
                successor.process(requset);
            }
        }
    }

    public class cto : manager
    {
        public cto(managertype managertype) : base(managertype)
        {
        }

        public override void process(requset requset)
        {
            if (requset.type == requesttype.leave && requset.number <= 5)
            {
                console.writeline($"cto 已批准 你的 {requset.content} 申请");
                return;
            }

            if (requset.type == requesttype.payrise && requset.number <= 500)
            {
                console.writeline($"cto 已批准 你的 {requset.content} 申请");
                return;
            }
            if (successor != null)
            {
                //交由下一级处理
                successor.process(requset);
            }
        }
    }

    public class ceo : manager
    {
        public ceo(managertype managertype) : base(managertype)
        {
        }

        public override void process(requset requset)
        {
            if (requset.type == requesttype.leave && requset.number <= 15)
            {
                console.writeline($"ceo 已批准 你的 {requset.content} 申请");
                return;
            }

            if (requset.type == requesttype.payrise && requset.number <= 1000)
            {
                console.writeline($"ceo 已批准 你的 {requset.content} 申请");
                return;
            }
            console.writeline($"ceo对你的 {requset.content} 申请 说:“小子,你有点飘啊!”");
        }
    }

客户端代码

    internal class program
    {
        private static void main(string[] args)
        {
            //创建领导
            var pm = new pm(managertype.pm);
            var cto = new cto(managertype.cto);
            var ceo = new ceo(managertype.ceo);
            //设置下一级处理者
            pm.setsuccessor(cto);
            cto.setsuccessor(ceo);

            //创建 请假请求
            var request1 = new requset
            {
                type = requesttype.leave,
                number = 5
            };
            pm.process(request1);
            console.writeline("\n");

            //创建 加薪请求
            var request2 = new requset
            {
                type = requesttype.payrise,
                number = 2000
            };
            pm.process(request2);

            console.writeline("\nhappy ending~");
            console.readline();
        }
    }

结果展示:

cto 已批准 你的 请假5天 申请

ceo对你的 加薪2000元 申请 说:“小子,你有点飘啊!”

这样我们也消除上面三个问题。当需求需要人事加入审批流程时,只需要增加一个继承manager的人事类;当需求要求不需要cto审批,直接由pm转到ceo时,我们只用修改pm的setsuccessor(),这也体现了职责链的灵活性。

示例代码地址: https://gitee.com/sayook/designmode/tree/master/chainofresponsibility