我们的很多功能当中都会遇到对版本进行过滤的场合,例如你可能需要对列表中的数据的时间进行过滤、版本过滤、渠道以及地区信息进行过滤。
原本的做法:设计很多个过滤方法,通过枚举的方式组合,选择需要过滤哪些方法,然后一个方法一个方法的调用。 这样的做法本身没什么问题。但是感觉很面向过程,不够面向对象。
通过学习.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 那句代码注释掉,再运行,由于没有过滤渠道,此时显示了两条数据
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对编程网的支持。如果你想了解更多相关内容请查看下面相关链接