zoukankan      html  css  js  c++  java
  • 小看--职责链模式

          职责链模式,是属于行为型设计模式,可以把一个请求分给多个对象处理的机会,可以避免发送者和处理者之间的耦合。

       (二)职责链模式的演变

          现在员工需要请假,请假审批规则如下:

          一天之内:组长审批通过即可,无需报送到部门经理;

          一天到三天:部门经理审批即可,无效报送到中心老大;

          三天到三十天:部门老大审批,无需报送到总裁办;

          大于三十天:总裁办审批;

          对于上面这个需求,开发者A拿到之后,马上写出了如下代码;

          1 、定义一个请假的上下文

     /// <summary>
        /// 请假的上下文
        /// </summary>
        public class ApplyContext {
            public int Id { get; set; }
            /// <summary>
            /// 发起人
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// 请假天数
            /// </summary>
            public int Day { get; set; }
    
            /// <summary>
            /// 请假描述
            /// </summary>
            public string Description { get; set; }
    
            /// <summary>
            /// 审批结果
            /// </summary>
            public bool AuditResult { get; set; }
    
            /// <summary>
            /// 审批备注
            /// </summary>
            public string AudtiRemark { get; set; }
        }

         2、根据需求,做了如下实现

              var applyContext=new ApplyContext()
                  {
                      Id =1,
                      Name ="小张",
                      Day =4,
                      Description ="老家有事" 
                  };
                   if (applyContext.Day <= 1)
                    {
                        Console.WriteLine("组长{0}审批....","groupleader");
                        applyContext.AuditResult = true;
                    }
                    if (applyContext.Day > 1 && applyContext.Day <= 3)
                    {
                        Console.WriteLine("部门经理{0}审批....", "groupleader");
                        applyContext.AuditResult = true;
                    }
                    //.....下面也是类似的,if-else这种做法。/
                }

          对于开发者A的做法,发现了这个基本上就是面向过程的编程,没有面向对象的思想(违法了单一职责原则),把所有东西都暴露到了上端。针对上面不好的地方,我们来改进我们的代码。

    下面是开发者B的做法。

          开发者B呢,就有一点面向对象的思想了,我们先把每个审批者提取出来,分别是组长,部门经理,中心老大,总裁。他们都有一个共同的操作,就是批假,再提取一个抽象出来(抽象类/接口),代码改进如下:

          1、先抽取一个抽象出来,这里我们用抽象类

     public abstract class AbstractAudtitor {
    
            /// <summary>
            /// 审批人的名字
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// 审批的方法
            /// </summary>
            /// <param name="context"></param>
            public abstract void Audit(ApplyContext context);
    
    
    
        }

          2、每个类,分别继承这个接口

    public class  CenterLeader:AbstractAudtitor {
    
            public override void Audit(ApplyContext context)
            {
                if (context.Day >3&&context.Day<=30) {
                    Console.WriteLine($"{this.Name},中心领导审批");
                    context.AuditResult = true;
                }
            }
        }

       上面代码,每个类都是类似的,在这里不一一列举;

       3、调用过程

      AbstractAudtitor groupLeader = new GroupLeader()
                    {
                        Name = "zhang",
                    };
                    groupLeader.Audit(applyContext);
                    if (!applyContext.AuditResult)
                    {
                        AbstractAudtitor deptManager = new DepartmentManager()
                        {
                            Name = "部门领导",
                        };
                        deptManager.Audit(applyContext);
                        if (!applyContext.AuditResult) {
                            AbstractAudtitor centerLeader = new CenterLeader() { Name = "中心老大" };
                            centerLeader.Audit(applyContext);
                        }
                        else if (!applyContext.AuditResult) {
                            AbstractAudtitor ceo = new CEO() { Name = "总裁办" };
                            ceo.Audit(applyContext);
                        }
                        else {
                            Console.WriteLine("领导不批准!");
                        }
                    }

         从上面可以看出,虽然我们现在是面向对象了,但是我们只是简单的翻译了一下需求,完全没有站在实际情况中去考虑, 因为实际情况中,不可能是你一个普通员工,说给请假条给部门领导,中心老大,总裁办的,而是由各个层级之间不断的转发,换句话说,上端不应该去找各个环节,应该是各个层级之间互相转发。

         那么接下来,开发者C根据刚刚所说,写了如下代码:

         主要思路是:既然你说上端不要直接去找各个环节,那么我们就把这个找的动作,放到每一个环节类的后面,也就是做如下改变

    public class CenterLeader : AbstractAudtitor {
    
            public override void Audit(ApplyContext context) {
                if (context.Day > 3 && context.Day <= 30) {
                    Console.WriteLine($"{this.Name},中心领导审批");
                    context.AuditResult = true;
                }
                else {
                    //在中心领导类里面,主动去找下一层,也就是总裁办的人。
                    new CEO() {Name = "zz"}.Audit(context);
                }
            }
        }

         其他类,也是做了如下改变。确实我们按照上面这样做法,很满足我们的现在的需求,可能有一天领导说:这个请假流程得变更一下,或者请假审批的下一级,应该是可以动态指定的,流程是可以动态配置的。

         为了满足这个需要,我们又要对上面的代码进行改进;

         根据领导说:流程是要可以动态指定的,行,按照设计模式的原则,封装不变的,变化的就抛出去,我们大概做了如下改进:我们提供一个SetNext(),设置下一个环节的方法。代码如下:

         因为每个环节都要提供一个SetNext方法,并且都需要一个AuditNext()的一个判断,所以我们就直接提供到父类AbstractAudtitor里面,具体代码如下:

         1 先完善了刚才的父类。

      public abstract class AbstractAudtitor {
    
            public string Name { get; set; }
    
            protected AbstractAudtitor _NextAuditor = null;
    
            /// <summary>
            /// 因为这个是父类,在这边写一个设置下一个环节的方法。
            /// </summary>
            /// <param name="audtitor"></param>
            public void SetNext(AbstractAudtitor audtitor) {
                this._NextAuditor = audtitor;
            }
    
            public abstract void Audit(ApplyContext context);
    
            //下一个环节审批
            protected void AuditNext(ApplyContext context) {
                if (this._NextAuditor != null) {
                    this._NextAuditor.Audit(context);
                }
                else {
                    context.AuditResult = false;
                    context.AudtiRemark = "不允许请假!";
                }
            }
    
    
    
        }

         2 调用方式如下:

      AbstractAudtitor groupLeader=new GroupLeader()
                    {
                        Name ="zz", 
                    };
                    AbstractAudtitor deptManager = new DepartmentManager() {
                        Name = "经理",
                    };
                    AbstractAudtitor centerLeader = new CenterLeader() {
                        Name = "中心领导",
                    };
                    AbstractAudtitor ceo = new CEO() {
                        Name = "CEO",
                    };
                    //设置下一个环节
                    groupLeader.SetNext(deptManager);
                    deptManager.SetNext(centerLeader);
                    centerLeader.SetNext(centerLeader);
                    //上面就是设置流程
    
                    //发起流程
                    groupLeader.Audit(applyContext);

          上面上端就可以对流程进行动态配置了,当然这里我们还需要用反射加配置文件的形式,把我们的流程做到更加可配置化。

        (三)职责链模式的优缺点

            优点:1 、请求者和处理者松耦合;2、职责明确,可动态配置。

            缺点:1、产生了很多细粒对象;2、要注意链的有效性。

           

          

         

              

  • 相关阅读:
    一分钟理解APM,把流失的用户找回来
    oauth2.0在监控宝项目中的应用一例
    数据路由,你造吗?
    Laravel的Ioc设计
    java使用默认线程池踩过的坑(三)
    java使用默认线程池踩过的坑(二)
    java使用默认线程池踩过的坑(一)
    hadoop中mapreduce的常用类(二)
    hadoop中mapreduce的常用类(一)
    16.9.5上午
  • 原文地址:https://www.cnblogs.com/gdouzz/p/8410558.html
Copyright © 2011-2022 走看看