从真实项目中抠出来的设计模式——第二篇:过滤器模式
一:实际场景介绍
我们在给用户做订单催付通知的时候,会有这样的一种场景,用户在系统后台设置一组可以催付的规则,比如说订单金额大于xx元,非黑名单用户,来自
哪个地区,已购买过某个商品,指定某个营销活动的人等等这样的条件,如果这时用户在淘宝上下了一个订单,那程序要判断的就是看一下此订单是否满足这
些规则中的某一个,如果满足,我们给他发送催付通知,这种场景是很多做CRM的同学都会遇到的问题,那针对这种场景,如何更好的规划业务逻辑呢?
二:普通的编程代码
在这里我们就不考虑多筛选条件下的性能,而只从代码维护复杂度考虑,如果不清楚设计模式的同学,大概会写出如下的代码:
1 namespace ConsoleApplication1 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 var regulars = new List<Regulars>(); 8 9 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则1", AnalysisConditons = "xxxx" }); 10 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则2", AnalysisConditons = "xxxx" }); 11 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则3", AnalysisConditons = "xxxx" }); 12 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则4", AnalysisConditons = "xxxx" }); 13 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则5", AnalysisConditons = "xxxx" }); 14 15 var filters = FilterRegularID(regulars); 16 filters = FilterRegularName(filters); 17 filters = FilterCondtions(filters); 18 19 //... 后续逻辑 20 } 21 22 static List<Regulars> FilterRegularID(List<Regulars> persons) 23 { 24 //过滤 “姓名” 的逻辑 25 return null; 26 } 27 28 static List<Regulars> FilterRegularName(List<Regulars> persons) 29 { 30 //过滤 “age” 的逻辑 31 return null; 32 } 33 34 static List<Regulars> FilterCondtions(List<Regulars> persons) 35 { 36 //过滤 “email” 的逻辑 37 return null; 38 } 39 } 40 41 /// <summary> 42 /// 各种催付规则 43 /// </summary> 44 public class Regulars 45 { 46 public int RegularID { get; set; } 47 48 public string RegularName { get; set; } 49 50 public string AnalysisConditons { get; set; } 51 } 52 }
为了演示,上面的代码是从regularid,regularname,condition三个维度对regulars这个聚合对象进行AND模式的筛选过滤,当过滤维度比较多的时候,这种写
法看的出来是简单粗暴,维护起来也必须简单粗暴, 所以上万行代码也就是这么出来的,设计模式告诉我们一个简单的“开闭原则”,那就是追求最小化的修改代码,这种
场景有更好的优化策略吗?对应到设计模式上就是“过滤器模式”,专门针对这种场景的解决方案,一个维度一个类,然后通过逻辑运算类将他们进行组合,可以看出这是一
种“结构式的设计模式”。
三:过滤器模式
好了,废话不多说,先来看一下优化后的设计图纸如下:
从上面这张图纸中可以看到,我已经将三个维度的过滤方法提取成了三个子类,由此抽象出了一个IFilter接口,当然你也可以定义成抽象类,然后实现了两个运算级
AND和OR子类Filter,用于动态的对原子性的RegularIDFilter,RegularNameFilter,ReuglarCondtionFilter进行AND,OR逻辑运算,下面我们再看具体代码:
1.IFilter
public interface IFilter { List<Regulars> Filter(List<Regulars> regulars); }
2. RegularIDFilter
1 public class RegularIDFilter : IFilter 2 { 3 /// <summary> 4 /// Regulars的过滤逻辑 5 /// </summary> 6 /// <param name="regulars"></param> 7 /// <returns></returns> 8 public List<Regulars> Filter(List<Regulars> regulars) 9 { 10 return null; 11 } 12 }
3.RegularNameFilter
1 public class RegularNameFilter : IFilter 2 { 3 /// <summary> 4 /// regularName的过滤方式 5 /// </summary> 6 /// <param name="regulars"></param> 7 /// <returns></returns> 8 public List<Regulars> Filter(List<Regulars> regulars) 9 { 10 return null; 11 } 12 }
4. RegularCondtionFilter
1 public class RegularCondtionFilter : IFilter 2 { 3 /// <summary> 4 /// Condition的过滤条件 5 /// </summary> 6 /// <param name="regulars"></param> 7 /// <returns></returns> 8 public List<Regulars> Filter(List<Regulars> regulars) 9 { 10 return null; 11 } 12 }
5.AndFilter
1 /// <summary> 2 /// filter的 And 模式 3 /// </summary> 4 public class AndFilter : IFilter 5 { 6 List<IFilter> filters = new List<IFilter>(); 7 8 public AndFilter(List<IFilter> filters) 9 { 10 this.filters = filters; 11 } 12 13 public List<Regulars> Filter(List<Regulars> regulars) 14 { 15 var regularlist = new List<Regulars>(regulars); 16 17 foreach (var criteriaItem in filters) 18 { 19 regularlist = criteriaItem.Filter(regularlist); 20 } 21 22 return regularlist; 23 } 24 }
6.OrFilter
1 public class OrFilter : IFilter 2 { 3 List<IFilter> filters = null; 4 5 public OrFilter(List<IFilter> filters) 6 { 7 this.filters = filters; 8 } 9 10 public List<Regulars> Filter(List<Regulars> regulars) 11 { 12 //用hash去重 13 var resultHash = new HashSet<Regulars>(); 14 15 foreach (var filter in filters) 16 { 17 var smallPersonList = filter.Filter(regulars); 18 19 foreach (var small in smallPersonList) 20 { 21 resultHash.Add(small); 22 } 23 } 24 25 return resultHash.ToList(); 26 } 27 }
7. 最后我们客户端调用程序就简单了,只要将“原子性”的过滤条件追加到“逻辑运算类”中就完美了,如下图:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var regulars = new List<Regulars>(); 6 7 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则1", AnalysisConditons = "xxxx" }); 8 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则2", AnalysisConditons = "xxxx" }); 9 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则3", AnalysisConditons = "xxxx" }); 10 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则4", AnalysisConditons = "xxxx" }); 11 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则5", AnalysisConditons = "xxxx" }); 12 13 //追加filter条件 14 var filterList = new IFilter[3] { 15 new RegularIDFilter(), 16 new RegularNameFilter(), 17 new RegularCondtionFilter() 18 }; 19 20 var andCriteria = new AndFilter(filterList.ToList()); 21 22 //进行 And组合 过滤 23 andCriteria.Filter(regulars); 24 25 } 26 }
当你仔细看完上面的代码,会不会发现,如果后续有需求变更,比如说增加筛选的维度,我只需要新增一个继承IFilter的子类就搞定了,客户端在调用的时候只要
在Filters集合中追加该筛选维度,是不是就OK了,所以这种模式几乎达到了无代码修改的地步~~~好了,本篇就说到了这里,希望对你有帮助~