如何构造请求处理对象链(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();
}
}
如何构造请求处理对象链(Pipeline)的更多相关文章
- 构造Json对象串工具类
import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.Property ...
- jQuery.buildFragment源码分析以及在构造jQuery对象的作用
这个方法在jQuery源码中比较靠后的位置出现,主要用于两处.1是构造jQuery对象的时候使用 2.是为DOM操作提供底层支持,这也就是为什么先学习它的原因.之前的随笔已经分析过jQuery的构造函 ...
- 9.19.1 反射构造Class对象
构造Class对象的三种方式: 第一种方式: (1)对于系统的类,必须写全名! (2)该方式会将.Cla ...
- js中的原型对象链
由于原型对象也是一个对象,它也有自己的原型对象并继承对象中的属性,这就是原型对象链:对象继承其原型对象,而原型对象继承它的原型对象,以此类推. 我们创建的每一个函数都有一个prototype(原型)属 ...
- jquery 1.7.2源码解析(二)构造jquery对象
构造jquery对象 jQuery对象是一个类数组对象. 一)构造函数jQuery() 构造函数的7种用法: 1.jQuery(selector [, context ]) 传入字符串参数:检查该字符 ...
- 4.构造Thread对象你也许不知道的几件事
1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际 ...
- jQuery源码分析-03构造jQuery对象-源码结构和核心函数
3. 构造jQuery对象 3.1源码结构 先看看总体结构,再做分解: (function( window, undefined ) { var jQuery = (function() { // 构 ...
- spring MVC之构造ModelAndView对象
spring MVC之构造ModelAndView对象 ---------- 构造ModelAndView对象 当控制器处理完请求时,通常会将包含视图名称或视图对象以及一些模型属性的ModelAndV ...
- Django中构造响应对象的方式
1 HttpResponse 可以使用django.http.HttpResponse来构造响应对象. HttpResponse(content=响应体, content_type=响应体数据类型, ...
随机推荐
- JSP中多条件判断
<c:if test="${result_map.connNew ne null and result_map.connNew ne 0}"> </c:if> ...
- <h2>1. mongodb介绍</h2>
1. mongodb介绍 2. ppt下载地址 http://download.csdn.net/detail/u014285882/7807105 阅读全文 本文已收录于下面专栏: mongodb使 ...
- Classification and Representation
Classification To attempt classification, one method is to use linear regression and map all predict ...
- SpringBoot学习:获取yml和properties配置文件的内容(转)
项目下载地址:http://download.csdn.net/detail/aqsunkai/9805821 (一)yml配置文件: pom.xml加入依赖: <!-- 支持 @Configu ...
- Android 各个版本号WebView
转载请注明出处 http://blog.csdn.net/typename/ powered by miechal zhao : miechalzhao@gmail.com 前言: 依据Googl ...
- NDK 配置及简单项目
转载请标明出处:http://blog.csdn.net/xx326664162/article/details/50998720 文章出自:薛瑄的博客 你也能够查看我的其它同类文章,也会让你有一定的 ...
- [Jenkins] Creating Application builds
After installing the jenkins, we start creating new job. 1. Give job names (your project name): 2. G ...
- 小强的HTML5移动开发之路(44)——JqueryMobile中的按钮
一.链接按钮 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...
- 数组filter方法对数组元素进行过滤
Array.prototype.filter对数组中元素进行过滤 /** * @method reduce * @param {number} item 当前迭代的数组元素 * @param {num ...
- Spirng setter 注入简单
1. 提供相应要注入的属性 //setter注入 public class Bean2 { private String name; private Integer age; // 提供要注 ...