Skip to content

Sc7-git/NanGua.Net

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NanGua

NanGua,基于中间件模式的代码优化解决方案。

NanGua为您提供了如下功能:
  嵌套解耦
  灵活封装
  嵌套并行(代码并行、逻辑并行)
  任务并行
  管道分支

NanGua最大的特点是解耦多层嵌套,嵌套之间独立,不依赖于上层嵌套,可以灵活封装成独立的函数。

注:NanGua目前提供了C#、JS版本。

Get Started


1、创建第一个NanGua

NanGua<object> mw = new NanGua<object>(null);
mw.Run();
//Output:中间件文档参考: https://github.com/Sc7-git/NanGua.Net

注:以上输出来自End默认值。


2、Use函数和两个重要参数:next、context

把NanGua看作一个管道;

context就是管道中流动的水,在代码中就理解为上下文对象;

next就是管道上的处理节点,如阀门、分流阀、净水器、滤网等一系列对水进行处理的工具,在代码中就理解为下一个中间件(传统意义上的中间件是指游走在操作系统和应用程序之间,但我认为这种在管道和水之间的处理节点也是一种中间件)。

Use就是在管道上添加处理节点,在代码中理解为注册中间件。之后介绍的Map、When都是基于Use的实现。注:注册完成所有中间件之后需要Run才能运行!

3、嵌套解耦、灵活封装、嵌套并行(代码并行、逻辑并行)
多个嵌套函数如何解耦?异步嵌套如何解耦?在不同场景下嵌套顺序不同如何封装(例:a函数中嵌套b函数,但是在另一场景又需要b函数嵌套a函数,此时该如何封装函数才能代码复用。在实际应用中可不止a、b两个函数。)?

NanGua<object> mw = new NanGua<object>(null);
//使用Use注册中间件
mw.Use(next => context =>{
    Console.WriteLine("第一个");
    //把上层嵌套中的代码挪到这里来
    //.... 省略业务逻辑
    //next是下一个中间件,也就是下层嵌套。根据业务场景决定是否调用。
    next(context);
})
//使用Use注册中间件
.Use(next => context =>{
    Console.WriteLine("第二个");
    //把下层嵌套中的代码挪到这里来
})
.Run();

灵活封装体现在可以把Use注册的中间件独立成一个函数,而非代码块。注:Use可以注册SimpleDelegate和Func<DelegateInput, DelegateOutput>两种类型委托。

static void Main(string[] args)
{
    NanGua<object> mw = new NanGua<object>(null);           
    mw.Use(A) //使用Use注册中间件
    .Use(B)//使用Use注册中间件
    .Run();
    Console.ReadKey();
}

//Func<DelegateInput<T>, DelegateOutput<T>>
static DelegateOutput<object> A(DelegateInput<object> next) =>
     context =>{
        Console.WriteLine(nameof(A));
        next(context);
    };

//SimpleDelegate<T>
static void B(DelegateInput<object> next, object context)
{
    Console.WriteLine(nameof(B));
    next(context);

}

4、管道分支
从宏观上看就是由单一管道结构转变为树形结构。
注意:map返回的是一个新的NanGua对象,同一个NanGua对象注册的map是同一层级的分支。所以mw.map()和mw.map()是同一级分支,但mw.map()和mw.map().map()则是上下级分支。不要因为链式编程的便捷而带来不必要的麻烦。
注意:因为map返回的并非原本的NanGua对象,所以一定是使用原本的NanGua对象执行Run。

例1:

NanGua<object> mw = new NanGua<object>(null);
var map1 = "map1";
var map2 = "map2";
mw.Use(next => context =>{
    Console.WriteLine("Use");
    //next(context, map1);
    next(context, map2);
});
mw.Map(map1, next => context => {
    Console.WriteLine(map1);
    next(context);
});
mw.Map(map2, next => context =>
{
    Console.WriteLine(map2);
    //next(context);
});
mw.Run();
//Output:Use
//Output:map2

例2:

NanGua<object> mw = new NanGua<object>(null);
var map1 = "map1";
var map2 = "map2";
var map1_1 = "map1.1";

mw.Use(next => context =>
{
    Console.WriteLine("Use");
    next(context, map1);
    //next(context, map2);
});

mw.Map(map1, next => context =>
{
    Console.WriteLine(map1);
    next(context, map1_1);
}).Map(map1_1, next => context =>
{
    Console.WriteLine(map1_1);
    next(context);
});
mw.Map(map2, next => context =>
{
    Console.WriteLine(map2);
    //next(context);
});
//Output:Use
//Output:map1
//Output:map1.1
//Output:中间件文档参考: https://github.com/Sc7-git/NanGua.Net

5、任务并行
实现了When、WhenAll、WhenOne,在js代码中用处更广,在c#异步编程中可以考虑使Task.WhenAll、Task.WhenAny替代。
WhenAll和WhenOne都是基于when的,所以只介绍When,When的第二个参数是设置延时对象的通过数量(0是默认所有),通过when可以自定义完成数量。
When是基于Use实现的,所以When和Use可以实现连接。
When的用法分三步:1、创建延迟对象,2、在注册函数中返回延延迟对象数组,3、异步任务执行完成后延迟对象调用Complete通知,当通知数量满足设置的通过数量时进入下一个中间件。

static void Main(string[] args)
{
    Stopwatch sw = new Stopwatch();
    NanGua<object> mw = new NanGua<object>(null);
    mw.When((context, createDelay) =>{
        sw.Start();
        //1、创建延迟对象
        var d1 = createDelay();
        var d2 = mw.CreateDelay();

        RequestAsync(3, () =>
        {
            Console.WriteLine("异步任务1完成了");
            //3、异步任务完成时回调通知
            d1.Complete();
        });
        RequestAsync(5, () =>
        {
            Console.WriteLine("异步任务2完成了");
            //3、异步任务完成时回调通知
            d2.Complete();
        });
        //2、在注册函数中返回所有申明的延迟对象
        return new NanGua<object>.Delay[] { d1, d2 };
    }, 1).Use(next => context =>{
         Console.WriteLine("Use");
         sw.Stop();
         Console.WriteLine(sw.Elapsed);
         next(context);
     })
      .Run();
    Console.ReadKey();
}

public async static void RequestAsync(int second, Action callBack)
{
    //模仿网络延迟
    await Task.Delay(second * 1000);
    callBack();
}

试试把上面代码中when第二个参数从1改为2、3看看效果是怎么样的。

其他:
One:第一个执行,只允许调用一次。
End:最后一个执行,允许多次调用。end不是附加,而是覆盖。注意End没有next;End是有默认值的。

Releases

No releases published

Packages

No packages published