前言

我正在写FastGithub这个小麻雀项目,里面主要涉及了Pipeline模式和Factory+Provider模式,这两种设计模式,让这个项目在"ip扫描"和"ip查找"两个核心功能上如鱼得水,在此分享给大家。

Pipeline

Pipeline模式也叫管道模式或流水线模式。通过预先设定好的一系列的阶段来处理输入的数据,每个阶段的输出即是下一个阶段的输入,每个阶段可以选择是否继续执行一下阶段。

上下文对象

在实现上,我们把所需的所有数据封装在上下文对象,每个阶段可以共享到同一份上下文对象。

中间件

在实现上,我们把每个阶段的处理封装为中间件,一个中间件可以访问到上下文对象和下一个阶段的处理对象,在执行时可以访问或修改上下文对象的数据。

实现详解

完整的Pipeline构建代码,详见https://github.com/xljiulang/FastGithub/tree/master/FastGithub.Core

阶段处理对象

/// <summary>
/// 表示所有中间件执行委托
/// </summary>
/// <typeparam name="TContext">中间件上下文类型</typeparam>
/// <param name="context">中间件上下文</param>
/// <returns></returns>
public delegate Task InvokeDelegate<TContext>(TContext context);

委托中间件

Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>>为一个委托中间件,第一个InvokeDelegate<TContext>表示传入的下一个处理阶段,第二个InvokeDelegate<TContext>表示当前处理阶段。

/// <summary>
/// 定义中间件管道创建者的接口
/// </summary>
/// <typeparam name="TContext">中间件上下文</typeparam>
public interface IPipelineBuilder<TContext>
{
/// <summary>
/// 使用中间件
/// </summary>
/// <param name="middleware">中间件</param>
/// <returns></returns>
IPipelineBuilder<TContext> Use(Func<InvokeDelegate<TContext>, InvokeDelegate<TContext>> middleware); /// <summary>
/// 创建所有中间件执行处理者
/// </summary>
/// <returns></returns>
InvokeDelegate<TContext> Build();
}

强类型中间件

我们可以把委托中间件,转换为如下的强类型中间件,InvokeAsync方法是本处理阶段,next参数,是委托中间件的下个阶段包装。

/// <summary>
/// 定义中间件的接口
/// </summary>
/// <typeparam name="TContext"></typeparam>
public interface IMiddleware<TContext>
{
/// <summary>
/// 执行中间件
/// </summary>
/// <param name="context">上下文</param>
/// <param name="next">下一个中间件</param>
/// <returns></returns>
Task InvokeAsync(TContext context, Func<Task> next);
}

使用详解

扫描任务分为完整扫描和历史结果扫描,使用的中间件有点差异,但都是把需要的中间件串起来就可以了。

/// <summary>
/// github扫描服务
/// </summary>
/// <param name="domainAddressFactory"></param>
/// <param name="scanResults"></param>
/// <param name="appService"></param>
/// <param name="logger"></param>
public GithubScanService(
DomainAddressFacotry domainAddressFactory,
GithubContextCollection scanResults,
IServiceProvider appService,
ILogger<GithubScanService> logger)
{
this.domainAddressFactory = domainAddressFactory;
this.scanResults = scanResults;
this.logger = logger; this.fullScanDelegate = new PipelineBuilder<GithubContext>(appService, ctx => Task.CompletedTask)
.Use<ConcurrentMiddleware>()
.Use<StatisticsMiddleware>()
.Use<TcpScanMiddleware>()
.Use<HttpsScanMiddleware>()
.Build(); this.resultScanDelegate = new PipelineBuilder<GithubContext>(appService, ctx => Task.CompletedTask)
.Use<StatisticsMiddleware>()
.Use<HttpsScanMiddleware>()
.Build();
}

Factory+Provider

多个Provider可以使用不同手段获取到github的ip,Factory再把各Provider得到的ip进行整合,他们都是得到相同的功能:拿到github的ip,只是各个Provider才是具体干活的,而且Provider之间没有任何有关系。

IDomainAddressProvider

/// <summary>
/// 定义域名的ip提值者
/// </summary>
interface IDomainAddressProvider
{
/// <summary>
/// 创建域名与ip的关系
/// </summary>
/// <returns></returns>
Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync();
}

DomainAddressFacotry

/// <summary>
/// 域名与ip关系工厂
/// </summary>
[Service(ServiceLifetime.Singleton)]
sealed class DomainAddressFacotry
{
private readonly IEnumerable<IDomainAddressProvider> providers; /// <summary>
/// 域名与ip关系工厂
/// </summary>
/// <param name="providers"></param>
public DomainAddressFacotry(IEnumerable<IDomainAddressProvider> providers)
{
this.providers = providers;
} /// <summary>
/// 创建域名与ip的关系
/// </summary>
/// <returns></returns>
public async Task<IEnumerable<DomainAddress>> CreateDomainAddressesAsync()
{
var hashSet = new HashSet<DomainAddress>();
foreach (var provider in this.providers)
{
var domainAddresses = await provider.CreateDomainAddressesAsync();
foreach (var item in domainAddresses)
{
hashSet.Add(item);
}
}
return hashSet;
}
}

模式优势分析

FastGithub同时使用了上述两种模式,其工作流程很简单:使用DomainAddressFacotry创建要扫描的ip,然后使用pipeline创建得到的扫描委托进行扫描即可。想得到更多的ip,增加一个DomainAddressProvider即可,不影响到其它任何代码流程,想在扫描过程中做其它扫描逻辑,增加一个扫描中间件并安装到合适位置即可。

Pipeline模式与Factory+Provider模式的应用的更多相关文章

  1. js原生设计模式——4安全的工厂方法模式之Factory方法模式

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  2. 工厂模式(Factory Method)

    1.工厂方法模式(Factory Method) 工厂方法模式分为三种: 1-1.普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建. 举例如下:(我们举一个发送邮件和短信的例子 ...

  3. 菜鸟理解的工厂模式(Factory Pattern)是什么样子的?

    直接开始说了,不浪费园友宝贵的时间! 什么是工厂模式? 在学习前,先问一下:"它是什么?". 工厂模式,它是项目里面常用的设计模式之一. 它是属于创建型模式,简单的理解创建型模式就 ...

  4. 设计模式之简单工厂模式Simple Factory(四创建型)

    工厂模式简介. 工厂模式专门负责将大量有共同接口的类实例化 工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类. 工厂模式有三种形态: 1.简单工厂模式Simple Factory ...

  5. 工厂模式(Factory)

    一.分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式主要分为三个,简单工厂模式(Simple Factory)/ 工厂方法模式(Fac ...

  6. C#设计模式系列:工厂方法模式(Factory Method)

    1. 工厂方法模式简介 1.1 定义 工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法模式是以一个类的实例化延迟到其子类. Factory Method模式用于在不指定待创建 ...

  7. Java设计模式之工厂模式(Factory)

    前言: 前面学习了建造者设计模式,接下来学习一下Retrofit中使用的另外一个设计模式,工厂设计模式!!!里面采用工厂模式使得数据转换得到完全解耦,工厂模式的好处用到了极致,如此好的设计模式我们怎能 ...

  8. Net设计模式实例之抽象工厂模式(Abstract Factory Pattern)

    一.抽象工厂模式简介(Bref Introduction) 抽象工厂模式(Abstract Factory Pattern),提供一个创建一系列相关或者相互依赖对象的接口,而无需制定他们的具体类.优点 ...

  9. .NET设计模式(2):1.2 抽象工厂模式(Abstract Factory)

    概述 抽象工厂模式(Abstract Factory)是所有形态的工厂模式中最为抽象和最具一般性的一种形态.抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口 ...

随机推荐

  1. Linux系统运行netstat命令时的过三关斩一将

    1.简介 这篇文章主要是记录在日常工作中遇到的一些问题,将其都总结整合到一起,方便查看,提高工作效率.小伙伴们看到标题可能觉得奇怪,不是过五关斩六将而是过三关斩一将.慢慢地往后看发现其中奥秘. 2.过 ...

  2. Django(21)migrate报错的解决方案

    前言 在讲解如何解决migrate报错原因前,我们先要了解migrate做了什么事情,migrate:将新生成的迁移脚本.映射到数据库中.创建新的表或者修改表的结构. 问题1:migrate怎么判断哪 ...

  3. linux如何patch打补丁

    1. 创建2个文件 1.txt 和 2.txt 并在1.txt基础上修改成为2.txt book@100ask:~/patch$ ls 1.txt 2.txt book@100ask:~/patch$ ...

  4. [bug] Maven项目缺少Maven Dependencies

    参考 https://blog.csdn.net/whitemiao/article/details/90177135

  5. Microk8s 安装helm3

    Microk8s 安装helm3 原本使用官方的命令时这样的.但是使用的是官方的源,网络极不稳定.就出现了下面的状况.解决方法是更改为国内的源. microk8s enable helm3 curl: ...

  6. Jsoup_Select 选择器

    Jsoup_Select 选择器 一,概述 可直接解析某个 URL 地址.HTML 文本内容.它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数 ...

  7. 从实例分析ELF格式的.gnu.hash区与glibc的符号查找

    前言 ELF格式的.gnu.hash节在设计上比较复杂,直接从glibc源码进行分析的难度也比较大.今天静下心来看了这篇精彩的文章,终于将布隆滤波器.算数运算转为位运算等一系列细节搞懂了(值得一提的是 ...

  8. shell字符截取

    shell字符截取 截取文本中以vm开头的单词 grep -o vm.* text | cut -d' '  -f1 截取活动主机

  9. 克隆 JavaScript

    克隆 浅克隆 浅克隆无法copy数组和对象 var obj = { name : "abs", age : '18', sex : 'male' } var obj1 = {} f ...

  10. 深入 Go 语言 defer 实现原理

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客: https://www.luozhiyun.com/archives/523 本文使用的go的源码 1.15.7 介绍 defer 执行规 ...