如何构造请求处理对象链(Pipeline)

在开发中,我们经常会遇到这样一个场景:传入一个对象,经过不同的节点对这个对象做不同的操作,比如ASP.NET Core 中的pipeline,IIS中的HTTPpipeline等。在这类问题中,往往我们允许用户可以自己定义自己的处理节点(Processor Node),能够实现这一目的的方式很多。本文中分享2种方式,欢迎大家交流。

责任链模式(Chain of Responsibility Pattern)

关于责任链模式的介绍园中已经有很多了,这里我就不再多余的来介绍了,直接上代码:

1. 创建抽象类

    public abstract class ProcessorExecution
    {
        protected ProcessorExecution Next { get; private set; }

        protected ProcessorExecution(ProcessorExecution next = null)
        {
            Next = next;
        }

        public virtual void Execute()
        {
            Next?.Execute();
        }

        public ProcessorExecution SetNext(ProcessorExecution next)
        {
            Next = next;
            return next;
        }
    }

2. 创建具体实现类

    public class Node1ProcessorExecution : ProcessorExecution
    {
        public Node1ProcessorExecution(ProcessorExecution next = null) : base(next)
        {
        }

        public override void Execute()
        {
            Console.WriteLine("Node1 Processor");
            base.Execute();
        }
    }

    public class Node2ProcessorExecution : ProcessorExecution
    {
        public Node2ProcessorExecution(ProcessorExecution next = null) : base(next)
        {
        }

        public override void Execute()
        {
            Console.WriteLine("Node2 Processor");
            base.Execute();
        }
    }

    public class Node3ProcessorExecution : ProcessorExecution
    {
        public Node3ProcessorExecution(ProcessorExecution next = null) : base(next)
        {
        }

        public override void Execute()
        {
            Console.WriteLine("Node3 Processor");
            base.Execute();
        }
    }

    public class TerminalProcessorExecute : ProcessorExecution
    {
        public TerminalProcessorExecute(ProcessorExecution next = null) : base(next)
        {
        }

        public override void Execute()
        {
            Console.WriteLine("Terminal Processor");
            base.Execute();
        }
    }

3. 调用对象链

    class Program
    {
        static void Main(string[] args)
        {
            var header = new Node1ProcessorExecution();
            header.SetNext(new Node2ProcessorExecution())
                .SetNext(new Node3ProcessorExecution())
                .SetNext(new TerminalProcessorExecute());
            header.Execute();

            Console.Read();
        }
    }

委托链

有时候我们很不情愿地为一个Processor Node 去创建一个新类,因为那样显得类文件特别多,毕竟每一个类中只有一个或很少的方法需要重写。这里,我们可以尝试第二种方法 ---- 委托链,帮助我们减少类的创建。

在C#中,委托是一种特殊的类的方式存在,所以我们可以使用委托的方式实现。话不多说,直接上代码:

1. 创建一个委托

我们需要创建一个委托用来替代 ProcessorExecution中的Execute方法(Processor Node 处理的逻辑核心),.NET 4.5提供了async的编程方法,这里我使用Task来作为该委托的返回值:

 public delegate Task ProcessorExecutionDelegate();

2. 创建一个Builder用于构造委托链

Builder中包括三个方法:

  • ProcessorExecutionBuilder Add(Func<ProcessorExecutionDelegate, ProcessorExecutionDelegate> execution): 用来维护Current -> Next的关系。我们需要创建一个表示 Func<ProcessorExecutionDelegate, ProcessorExecutionDelegate> 的集合 _components
  • ProcessorExecutionBuilder Add(Func<Func<Task>, Task> middleware):用来表述NodeXProcessorExecution类(Func<Func<Task>, Task> middleware),内部调用Add(Func<ProcessorExecutionDelegate, ProcessorExecutionDelegate> execution)
  • ProcessorExecutionDelegate Build():构造委托链,并返回Header节点
    public class ProcessorExecutionBuilder
    {
        private readonly List<Func<ProcessorExecutionDelegate, ProcessorExecutionDelegate>> _components = new List<Func<ProcessorExecutionDelegate, ProcessorExecutionDelegate>>();

        private ProcessorExecutionBuilder Add(Func<ProcessorExecutionDelegate, ProcessorExecutionDelegate> execution)
        {
            _components.Add(execution);
            return this;
        }

        public ProcessorExecutionBuilder Add(Func<Func<Task>, Task> middleware)
        {
            Add((next) => () =>
            {
                Func<Task> func = () => next();
                return middleware(func);
            });
            return this;
        }

        public ProcessorExecutionDelegate Build()
        {
            var next = (ProcessorExecutionDelegate)(() => Task.Run(() => { Console.WriteLine("Terminal Processor"); }));
            _components.Reverse();
            foreach (var item in _components)
            {
                next = item(next);
            }

            return next;
        }
    }

3. 调用对象链

    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ProcessorExecutionBuilder();
            builder.Add((next) =>
                {
                    Console.WriteLine("Node1 Processor");
                    return next();
                })
                .Add((next) =>
                {
                    Console.WriteLine("Node2 Processor");
                    return next();
                }).Add((next) =>
                {
                    Console.WriteLine("Node3 Processor");
                    return next();
                });

            builder.Build().Invoke();
            Console.Read();
        }
    }

猜你喜欢

转载自www.cnblogs.com/yangtam/p/9024338.html