前言

我正在写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. python三元(三目)运算

    传统的if,else写法 三元运算 name="alex" if 1==1 else "SB"

  2. XAML一些控件的使用

    这节来讲一些XAML中常用控件的使用. Window Window控件是一个基础,它是其它控件的容器,我们可以通过修改其中的一些属性来设置窗体的显示效果,下面说一些最常用的属性: WindowStar ...

  3. FFmpeg应用实践之命令查询

    0. 前言 FFmpeg 中常用的工具有三个,分别是多媒体编解码工具ffmpeg.多媒体内容分析工具ffprobe和多媒体播放器ffplay.本文介绍的指令都是与编解码工具 ffmpeg 相关的. 学 ...

  4. Alpha事后分析

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件的功能主要是让一些基于表单识别的项目(如微软智能表单识别项目)减少在数据生成方面上浪费的 ...

  5. 『动善时』JMeter基础 — 14、使用JMeter发送Post请求

    目录 1.Post请求参数类型说明 2.用于演示的项目说明 3.发送Post请求示例 (1)测试计划内包含的元件 (2)请求参数类型为x-www-form-urlencoded 4.请求参数form- ...

  6. C#·对于BOM头之完全解决方案

    阅文时长 | 0.46分钟 字数统计 | 798.4字符 主要内容 | 1.引言&背景 2.使用C#写入带有/不带有BOM头的文件? 3.对于读取文件时,避免BOM头造成的异常. 4.声明与参 ...

  7. [bug] powerdesigner 设置id 自增 Properties中没有identity

    参考 https://blog.csdn.net/qq_37924509/article/details/105215719

  8. Vim删除空行

    Vim删除空行 1 Vim删除空行 打开vim输入:g/^$/d :g将在与正则表达式匹配的行上执行命令. 正则表达式是'空行',命令是:d (删除)

  9. python从hello world开始(3)

    """# !usr/bin/env python# -*- coding:utf-8 _*-""""""@Au ...

  10. 二进制部署K8S-2集群部署

    二进制部署K8S-2集群部署 感谢老男孩教育王导的公开视频,文档整理自https://www.yuque.com/duduniao/k8s. 因为在后期运行容器需要有大量的物理硬件资源使用的环境是用的 ...