作者:潘月飞--_758 | 来源:互联网 | 2023-02-04 04:51
前言我正在写FastGithub这个小麻雀项目,里面主要涉及了Pipeline模式和Factory+Provider模式,这两种设计模式,让这个项目在ip扫描和ip查找两个
前言
我正在写FastGithub这个小麻雀项目,里面主要涉及了Pipeline模式和Factory+Provider模式,这两种设计模式,让这个项目在"ip扫描"和"ip查找"两个核心功能上如鱼得水,在此分享给大家。
Pipeline
Pipeline模式也叫管道模式或流水线模式。通过预先设定好的一系列的阶段来处理输入的数据,每个阶段的输出即是下一个阶段的输入,每个阶段可以选择是否继续执行一下阶段。
上下文对象
在实现上,我们把所需的所有数据封装在上下文对象,每个阶段可以共享到同一份上下文对象。
中间件
在实现上,我们把每个阶段的处理封装为中间件,一个中间件可以访问到上下文对象和下一个阶段的处理对象,在执行时可以访问或修改上下文对象的数据。
实现详解
完整的Pipeline构建代码,详见https://github.com/xljiulang/FastGithub/tree/master/FastGithub.Core
阶段处理对象
///
/// 表示所有中间件执行委托
///
/// 中间件上下文类型
/// 中间件上下文
///
public delegate Task InvokeDelegate(TContext context);
委托中间件
Func, InvokeDelegate>
为一个委托中间件,第一个InvokeDelegate
表示传入的下一个处理阶段,第二个InvokeDelegate
表示当前处理阶段。
///
/// 定义中间件管道创建者的接口
///
/// 中间件上下文
public interface IPipelineBuilder
{
///
/// 使用中间件
///
/// 中间件
///
IPipelineBuilder Use(Func, InvokeDelegate> middleware);
///
/// 创建所有中间件执行处理者
///
///
InvokeDelegate Build();
}
强类型中间件
我们可以把委托中间件,转换为如下的强类型中间件,InvokeAsync方法是本处理阶段,next参数,是委托中间件的下个阶段包装。
///
/// 定义中间件的接口
///
///
public interface IMiddleware
{
///
/// 执行中间件
///
/// 上下文
///
下一个中间件
///
Task InvokeAsync(TContext context, Func next);
}
使用详解
扫描任务分为完整扫描和历史结果扫描,使用的中间件有点差异,但都是把需要的中间件串起来就可以了。
///
/// github扫描服务
///
///
///
///
///
public GithubScanService(
DomainAddressFacotry domainAddressFactory,
GithubContextCollection scanResults,
IServiceProvider appService,
ILogger logger)
{
this.domainAddressFactory = domainAddressFactory;
this.scanResults = scanResults;
this.logger = logger;
this.fullScanDelegate = new PipelineBuilder(appService, ctx => Task.CompletedTask)
.Use()
.Use()
.Use()
.Use()
.Build();
this.resultScanDelegate = new PipelineBuilder(appService, ctx => Task.CompletedTask)
.Use()
.Use()
.Build();
}
Factory+Provider
多个Provider可以使用不同手段获取到github的ip,Factory再把各Provider得到的ip进行整合,他们都是得到相同的功能:拿到github的ip,只是各个Provider才是具体干活的,而且Provider之间没有任何有关系。
IDomainAddressProvider
///
/// 定义域名的ip提值者
///
interface IDomainAddressProvider
{
///
/// 创建域名与ip的关系
///
///
Task> CreateDomainAddressesAsync();
}
DomainAddressFacotry
///
/// 域名与ip关系工厂
///
[Service(ServiceLifetime.Singleton)]
sealed class DomainAddressFacotry
{
private readonly IEnumerable providers;
///
/// 域名与ip关系工厂
///
///
public DomainAddressFacotry(IEnumerable providers)
{
this.providers = providers;
}
///
/// 创建域名与ip的关系
///
///
public async Task> CreateDomainAddressesAsync()
{
var hashSet = new HashSet();
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即可,不影响到其它任何代码流程,想在扫描过程中做其它扫描逻辑,增加一个扫描中间件并安装到合适位置即可。