zoukankan      html  css  js  c++  java
  • 模仿DotnetCore中间件的方式,做一个列表过滤的功能

    我们的很多功能当中都会遇到对版本进行过滤的场合,例如你可能需要对列表中的数据的时间进行过滤、版本过滤、渠道以及地区信息进行过滤。

     原本的做法:设计很多个过滤方法,通过枚举的方式组合,选择需要过滤哪些方法,然后一个方法一个方法的调用。 这样的做法本身没什么问题。但是感觉很面向过程,不够面向对象。

     

     通过学习.Net Core的源码,我们可以了解到它采用了一种委托链表的方式,将所有的中间件都串了起来。所以我想要仿造它这个去实现一下这个功能。

    这样做的好处:抽象出一些过滤的方法,对于不同的系统,只要通过Use方法,就可以增加我们的过滤规则,考虑到不同的系统过滤的规则不同,这样做也比较灵活(例如 应用管理系统 需要过滤版本、渠道、地区 ,而黑白名单需要过滤版本、渠道、时间等等,那么对于前者我只需要在过滤的时候 UseVersion UserChannel UseArea, 对于后者把UserArea缓存UseTime即可。)

    废话不多说:上码

    1.定义一个委托类型,承载我们过滤方法

    namespace FilterDelegate
    {
          public delegate IEnumerable<TcySysApplication> TcySysFilterDelegate(IEnumerable<TcySysApplication> applist, TcySysFilterConditionInfo conditionInfo );
    }
    

    委托的输入是我们待处理的数据列表appList, 以及我们执行过滤的条件数据。

    2.定义一个Builder类,主要用于构建我们整个过滤器,里面主要有两个方法Use方法以及Build方法,Use方法主要用于往我们的委托列表里面增加过滤委托,Build方法主要用于生成最后的过滤器

    private readonly IList<Func<TcySysFilterDelegate, TcySysFilterDelegate>> _components = new List<Func<TcySysFilterDelegate, TcySysFilterDelegate>>();
    
    public TcySysFilterBuilder()
    {
    
    }
    
    public TcySysFilterBuilder Use(Func<TcySysFilterDelegate, TcySysFilterDelegate> filterItem)
    {
        _components.Add(filterItem);
        return this;
    }
    
    public TcySysFilterDelegate Build()
    {
        TcySysFilterDelegate last = (applist,filterInfo) =>
        {
            Console.WriteLine("过滤完成");
            return applist;
        };
    
        foreach (var component in _components.Reverse())
        {
            last = component(last);
        }
    
        return last;
    }
    

    3.定义一堆过滤方法,这里没有写具体的逻辑,每一个方法都是通过Builder.Use将委托加入到委托链中

    public static TcySysFilterBuilder UseTimeFilter(this TcySysFilterBuilder builder)
    {
        return builder.Use(next =>
        {
            return (list, filterInfo) =>
            {
                Console.WriteLine("我是时间过滤");
                return next(list, filterInfo);
            };
        });
    }
    
    
    public static TcySysFilterBuilder UseChannelFilter(this TcySysFilterBuilder builder)
    {
        return builder.Use(next =>
        {
            return (list, filterInfo) =>
            {
                Console.WriteLine("我是渠道过滤");
    
                list = list.Where(x => x.ChannelId != filterInfo.ChannelId);
    
                return next(list, filterInfo);
            };
        });
    }
    
    public static TcySysFilterBuilder UseVersionFilter(this TcySysFilterBuilder builder)
    {
        return builder.Use(next =>
        {
            return (list, filterInfo) =>
            {
                Console.WriteLine("我是版本过滤");
                return next(list, filterInfo);
            };
        });
    }
    

    4.其他类型

    public class TcySysApplication
    {
        public long AppId { set; get; }
        public string Name { set; get; }
        public long ChannelId { set; get; }
        public long Version { set; get; }
        public string Province { set; get; }
        public string City { set; get; }
        public string District { set; get; }
    }
    
    public class TcySysFilterConditionInfo
    {
        public long ChannelId { set; get; }
        public long Version { set; get; }
        public string Province { set; get; }
        public string City { set; get; }
        public string District { set; get; }
    }
    

    5.执行使用

    class Program
    {
        static void Main(string[] args)
        {
            var sourceList = new List<TcySysApplication>();
    
            sourceList.Add(new TcySysApplication {
                AppId =1000,
                ChannelId = 88215,
                District = "",
                City = "乌鲁木齐",
                Province = "新疆",
                Name ="爱玩不玩",
                Version = 10001
            });
    
            sourceList.Add(new TcySysApplication
            {
                AppId = 1001,
                ChannelId = 310200,
                District = "",
                City = "乌鲁木齐",
                Province = "新疆",
                Name = "爱玩不玩2",
                Version = 10002
            });
    
    
            var filterInfo = new TcySysFilterConditionInfo
            {
                ChannelId = 310200,
                District = "",
                City = "北京",
                Province = "北京",
                Version = 10002
            };
    
    
            var builder = new TcySysFilterBuilder();
    
            builder.UseTimeFilter()
                .UseChannelFilter()
                .UseVersionFilter();
    
            var filter = builder.Build();
    
            var result = filter(sourceList, filterInfo);
    
    
            foreach (var item in result)
            {
                Console.WriteLine($"AppId={item.AppId} AppName={item.Name} ChannelId={item.ChannelId}");
            }
    
            Console.ReadKey();
        }
    }
    

    图上我使用了三种过滤,其中因为Channel中有过滤的逻辑,根据这个逻辑我们应该只会返回一个Channeld = 88215的数据

    我们可以将 UseChannelFilter 那句代码注释掉,再运行,由于没有过滤渠道,此时显示了两条数据

  • 相关阅读:
    2. Git基础命令
    1.Git基础配置
    demo_49 大结局
    demo_48 上传图片实现
    demo_47 反馈图片选择功能实现
    demo_46 问题反馈页面实现
    gitlab +jenkins
    面试分析
    面试基础 一文件操作和程序进程
    man 命令帮助文档的使用
  • 原文地址:https://www.cnblogs.com/dcz2015/p/11867187.html
Copyright © 2011-2022 走看看