【问题标题】:Chain of Responsibility Dynamic Chain责任链动态链
【发布时间】:2018-11-12 22:18:31
【问题描述】:

我正在开发一个使用责任链来处理请求的应用程序。我知道如何构建链,但是如果您看下面的示例,我将不得不调用link1.Process(request); 来启动链过程。我想弄清楚的是,有没有办法把它当作一个集合来处理,可以只调用链的第一个链接,不管它是什么?原因是,我知道基本元素是什么(最终的默认对象),但是其他程序员可以将对象添加到链中,并可能将它们放在链永远无法到达它们的位置。

public class MergedFieldProcessor
{

    public MergedFieldProcessor()
    {
        //Define CoR here

       FieldProcessor link1 = new FieldProcessor();
       FieldProcessor link2 = new FieldProcessor();
       FieldProcessor link3 = new FieldProcessor();

       link1.SetNextProcessor(link2);
       link2.SetNextProcessor(link3);

    }



}

public abstract class FieldProcessor
{
    private FieldProcessor NextProcessor { get; set; }

    public FieldProcessor()
    {
        this.NextProcessor = new SprocObject();
    }

    public void SetNext (FieldProcessor successor)
    {
       this.NextProcessor = successor;
    }

    //determines if this link in the change is responsible for the request
    public abstract Boolean WillProcess(MergedFieldProcessorRequest request);

    //performs the processing required for the tag
    public abstract void ProcessField(MergedFieldProcessorRequest request);


    //chain method that passes the request
    public void ProcessRequest(MergedFieldProcessorRequest request)
    {
        if (!this.WillProcess(request))
            this.NextProcessor.ProcessRequest(request);
        else
            this.ProcessField(request);
    }


}

public class MergedFieldProcessorRequest
{
    public MergedField Field { get; set; }

    public Dictionary<string, string> SearchParams { get; set; }
}

无法访问的链接示例:

FieldProcessor link1 = new FieldProcessor();
        FieldProcessor link2 = new FieldProcessor();
        FieldProcessor link3 = new FieldProcessor();
        FieldProcessor link4 = new FieldProcessor();

        link4.SetNext(link1);
        link1.SetNext(link2);
        link2.SetNext(link3);

如果他们没有将启动进程的代码修改为 link4.Process(request),那么 link4 将永远不会成为链的一部分。

简而言之,是否可以动态构建链,以便如果有人将对象添加到集合中,它会自动添加到链中?

【问题讨论】:

  • 你想太多了。如果您的消费者遗漏了链接,则很可能是故意的。如果他们不这样做,那就是他们的错。这类似于强制编译器确保 while 循环被关闭,只是因为可以使用 while 循环进行无限循环。
  • 所有这一切看起来你没有使用 C# 和 .Net 提供的任何好的特性。这背后的真正需求是什么?我确信有更好的方法来实现您的需求,例如 MEF。

标签: c# design-patterns chain-of-responsibility


【解决方案1】:

您想让用户能够构建链......但没有构建链的能力吗?
要么用户负责链接对象,要么放弃链接并为FieldProcessors 提供任何集合(然后按它们在集合中的顺序调用它们)。

如果链接很重要,您可以做的最好的事情是在处理之前对循环和无法访问的链接进行链验证。

【讨论】:

    【解决方案2】:

    这是我想出的解决方案。只需将每个处理器添加到集合中,然后遍历该集合以构建链,并处理链,只需调用 this.Links[0].Process(request);

     #region Build Chain Collection;
            this.Links = new List<FieldProcessor>()
            {
                new StudentEnrollmentDetailsProcessor(),
                new SprocObject()
            };
            #endregion; 
    
            #region Build Chain Dynamically
            for (int i = 0; i < this.Links.Count(); i++)
            {
                if (i < this.Links.Count())
                {
                    this.Links[i].SetNext(this.Links[i + 1]);
                }
            }
            #endregion;
    

    【讨论】:

      【解决方案3】:

      你可以使用反射和一些递归

      public class MergedFieldProcessor
      {
          private FieldProcessor first;
      
          private FieldProcessor CreateLink(IEnumerator<Type> processors)
          {
              if(processors.MoveNext())
              {
                  FieldProcessor link = (FieldProcessor)Activator.CreateInstance(processors.Current);
                  link.NextProcessor = CreateLink(processors);
                  return link;
              }
              return null;
          }
      
          public MergedFieldProcessor()
          {
              var processType = typeof(FieldProcessor);
              var allProcess = processType.Assembly.GetTypes()
                  .Where(t => t != processType && processType.IsAssignableFrom(t));
              first = CreateLink(allProcess.GetEnumerator());
          }
      
          public void Handle(MergedFieldProcessorRequest request)
          {
              first.ProcessRequest(request);
          }
      }
      

      这将确保创建所有可能的链接并将其链接在一起,但需要注意的是:最后一个链接将有一个 null 继任者,并且通常它必须是一个更接近的链接(将处理任何请求)。

      【讨论】:

        【解决方案4】:
        public abstract class AbCommon
        {
            public virtual AbCommon Successor { get; protected set; }
        
            public virtual void Execute()
            {           
                if (Successor != null)
                {
                    Successor.Execute();
                }
            }
        
            public virtual void SetSuccessor(AbCommon successor)
            {
                if (Successor != null)
                {
                    Successor.SetSuccessor(successor);
                }
                else
                {
                    this.Successor = successor;
                }
            }
        }
        
        class DefaultClass : AbCommon
        {   
            public override void Execute()
            {
                Console.WriteLine("DC");
                base.Execute();
            }       
        }
        
        class FirstClass: AbCommon
        {
            public override void Execute()
            {
                Console.WriteLine("FC");
                base.Execute();
            }
        }
        
        class SecondClass: AbCommon
        {   
            public override void Execute()
            {
                Console.WriteLine("SC");
                base.Execute();
            }
        }
        
        class ThirdClass: AbCommon
        {
            public override void Execute()
            {
                Console.WriteLine("TC");
                base.Execute();
            }
        }
        

        并将这些用作

         class Program
          {
            static void Main(string[] args)
            {
                DefaultClass dc = new DefaultClass();
        
                    FirstClass fc = new FirstClass();
                    dc.SetSuccessor(fc);
        
                    SecondClass sc = new SecondClass();
                    dc.SetSuccessor(sc);
        
                    ThirdClass tc = new ThirdClass();
                    dc.SetSuccessor(tc);
        
                    dc.Execute();
        }}
        

        您可以动态添加或删除对象

        【讨论】:

          猜你喜欢
          • 2020-02-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-02-05
          • 2021-07-21
          相关资源
          最近更新 更多