在开发中,我们经常会遇到这样一个场景:传入一个对象,经过不同的节点对这个对象做不同的操作,比如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. [Angular] @ContentChild with Directive ref

    For example you have a component, which take a trasclude input element: <au-fa-input id="pas ...

  2. 服务器svn 小乌龟 visualsvn server manager Tortoisesvn的部署使用

    这个主要说说实现hook,就是本地上传文件后,服务器svn将相应的文件也修改了,实现本地上传,可以及时在浏览器查看效果 首先安装visualsvn 可参考http://blog.csdn.net/zl ...

  3. PWA之Web 应用清单

    原文 简书原文:https://www.jianshu.com/p/5c96242188e8 大纲 1.什么是Web 应用清单 2.“清单文件”:Web App Manifest 规范的应用 3.we ...

  4. php求二叉树的深度(1、二叉树就可以递归,因为结构和子结构太相似)(2、谋而后动,算法想清楚,很好过的)

    php求二叉树的深度(1.二叉树就可以递归,因为结构和子结构太相似)(2.谋而后动,算法想清楚,很好过的) 一.总结 1.二叉树就可以递归,因为结构和子结构太相似 2.谋而后动,算法想清楚,很好过的 ...

  5. MySQL 监控-innotop

    innotop 编写者Balon Schwartz,<高性能MySQL>的作者之一. innotop的作用为实时地展示服务器正在发生的事情,监控innodb,监控多个MySQL实例,是一款 ...

  6. 对Fragment切换的优化

    在项目中需要进行Fragment的切换,一直都是用replace()方法来替换Fragment:然后总感觉切换的时候有些卡顿,原来的代码 /** * 切换页面,这里采用回调 * * @param f ...

  7. 【转】C++11 并发指南五(std::condition_variable 详解)

    http://www.cnblogs.com/haippy/p/3252041.html 前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三 ...

  8. [SVG] Optimize SVGs for Better Performance using svgo

    Just like a bitmap image, you can compress an SVG by removing various pieces of code that aren’t nec ...

  9. Android中再按一次退出实现

    很多应用中都有一个在用户后退的时候显示"再按一次退出"的提醒,这个怎么实现呢?有两种方式 第一种方式(最常用) long waitTime = 2000; long touchTi ...

  10. 【Python 安装】安装第三方库时 PermissionError: [WinError 5] Access is denied

    对于 windows 用户,在开始菜单中输入 cmd,右键以 run as administrator(以管理员身份运行). Python - PIP install trouble shooting ...