在开发中,我们经常会遇到这样一个场景:传入一个对象,经过不同的节点对这个对象做不同的操作,比如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();
}
}

如何构造请求处理对象链(Pipeline)的更多相关文章

  1. 构造Json对象串工具类

    import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.Property ...

  2. jQuery.buildFragment源码分析以及在构造jQuery对象的作用

    这个方法在jQuery源码中比较靠后的位置出现,主要用于两处.1是构造jQuery对象的时候使用 2.是为DOM操作提供底层支持,这也就是为什么先学习它的原因.之前的随笔已经分析过jQuery的构造函 ...

  3. 9.19.1 反射构造Class对象

    构造Class对象的三种方式:         第一种方式:                     (1)对于系统的类,必须写全名!                     (2)该方式会将.Cla ...

  4. js中的原型对象链

    由于原型对象也是一个对象,它也有自己的原型对象并继承对象中的属性,这就是原型对象链:对象继承其原型对象,而原型对象继承它的原型对象,以此类推. 我们创建的每一个函数都有一个prototype(原型)属 ...

  5. jquery 1.7.2源码解析(二)构造jquery对象

    构造jquery对象 jQuery对象是一个类数组对象. 一)构造函数jQuery() 构造函数的7种用法: 1.jQuery(selector [, context ]) 传入字符串参数:检查该字符 ...

  6. 4.构造Thread对象你也许不知道的几件事

    1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际 ...

  7. jQuery源码分析-03构造jQuery对象-源码结构和核心函数

    3. 构造jQuery对象 3.1源码结构 先看看总体结构,再做分解: (function( window, undefined ) { var jQuery = (function() { // 构 ...

  8. spring MVC之构造ModelAndView对象

    spring MVC之构造ModelAndView对象 ---------- 构造ModelAndView对象 当控制器处理完请求时,通常会将包含视图名称或视图对象以及一些模型属性的ModelAndV ...

  9. Django中构造响应对象的方式

    1 HttpResponse 可以使用django.http.HttpResponse来构造响应对象. HttpResponse(content=响应体, content_type=响应体数据类型, ...

随机推荐

  1. 经验总结56--mybatis返回主键

    使用mybatis框架时,有时候须要新插入的数据的主键是多少. 1.oracle 因为oracle是建的序列文件,获取ID值. <insert id="insert" par ...

  2. 关于用strace工具定位vrrpd进程有时会挂死的bug

    只做工作总结备忘之用. 正在烧镜像,稍总结一下进来改bug遇到的问题. 一个项目里要用到L3 switch的nat,vrrp功能,但实地测试中偶然出现write file挂死的情况,但不是必现.交付在 ...

  3. 在vue中使用nprogress

    NProgress的官网:http://ricostacruz.com/nprogress/        源码地址:https://github.com/rstacruz/nprogress 1.安 ...

  4. IDEA使用从Eclipse过来的快捷键

    1.Eclipse中的ctrl+shift+o --------> Ctrl + Alt + O 2.Eclipse中快捷键是Ctrl+O ---------> MacOS 下是 cmd+ ...

  5. request与response对象详述

    request与response对象. 1. request代表请求对象 response代表的响应对象. 学习它们我们可以操作http请求与响应. 2.request,response体系结构. 在 ...

  6. NetSnmp配置

    http://blog.csdn.net/shanzhizi/article/details/16985989

  7. 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(3)输入输出函数

    一.基本的输入和输出函数的用法 1.printf()  //屏幕输出 用法: (1)printf("字符串\n"); (2)printf("输出控制符", 输出 ...

  8. PHP移动互联网开发笔记(3)——运算符与流程控制

    一.PHP的运算符 PHP中有丰富的运算符集,它们中大部分直接来自于C语言.按照不同功能区分,运算符可以分为:算术运算符.字符串运算符.赋值运算符.位运算符.条件运算符,以及逻辑运算符等.当各种运算符 ...

  9. 使用JSONP解决跨域问题-代码示例

    前段时间用JSONP解决了跨域问题,现在不用了,把代码思路记下来,今后说不定还用得上. JS代码 //查询公告数据 function recentpost(){ $.getJSON(cmsUrl+&q ...

  10. C语言编写静态链接库及其使用

    本篇讲述使用C语言编写静态链接库,而且使用C和C++的方式来调用等. 一.静态库程序:执行时不独立存在,链接到可执行文件或者动态库中,目标程序的归档. 1.用C编写静态库步骤 a.建立项目(Win32 ...