zoukankan      html  css  js  c++  java
  • 设计模式-职责链模式(ChainOfResponsibility)

    讲故事

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

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

    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("
    ");
    
                //创建 加薪请求
                var request2 = new Requset
                {
                    Type = RequestType.PayRise,
                    Number = 2000
                };
                pm.Process(request2);
                cto.Process(request2);
                ceo.Process(request2);
    
                Console.WriteLine("
    Happy 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("
    ");
    
                //创建 加薪请求
                var request2 = new Requset
                {
                    Type = RequestType.PayRise,
                    Number = 2000
                };
                pm.Process(request2);
    
                Console.WriteLine("
    Happy Ending~");
                Console.ReadLine();
            }
        }
    

    结果展示:

    CTO 已批准 你的 请假5天 申请
    
    CEO对你的 加薪2000元 申请 说:“小子,你有点飘啊!”
    

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

    示例代码地址: https://gitee.com/sayook/DesignMode/tree/master/ChainOfResponsibility

  • 相关阅读:
    ImageWatch 无法安装在VS2017环境下的解决方案
    Android CmakeList
    Android 工程越来越大,运行变卡解决方法
    奥卡姆剃刀(简约之法则)
    Cmake时 如何在windows命令行 选择vs版本
    ubuntu 18.04 安装tensorflow 2 cuda10 CUDNN Anaconda3
    Centos7简易通过yum安装phpmyadmin
    centos7 nigx 免费永久获取 Let‘s Encrypt 证书
    Execution failed for task ':app:compileDebugJavaWithJavac'
    centos 安装aconda
  • 原文地址:https://www.cnblogs.com/sayook/p/12788180.html
Copyright © 2011-2022 走看看