zoukankan      html  css  js  c++  java
  • 从真实项目中抠出来的设计模式——第二篇:过滤器模式

    一:实际场景介绍

         我们在给用户做订单催付通知的时候,会有这样的一种场景,用户在系统后台设置一组可以催付的规则,比如说订单金额大于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了,所以这种模式几乎达到了无代码修改的地步~~~好了,本篇就说到了这里,希望对你有帮助~

  • 相关阅读:
    【HDOJ】4412 Sky Soldiers
    【HDOJ】4579 Random Walk
    【HDOJ】4418 Time travel
    【HDOJ】4326 Game
    【HDOJ】4089 Activation
    【HDOJ】4043 FXTZ II
    【HDOJ】4652 Dice
    【HDOJ】3007 Buried memory
    mfc调用WPFDLL
    遍历系统中所有的进程,可根据名字或ID查找某一个线程
  • 原文地址:https://www.cnblogs.com/huangxincheng/p/6415393.html
Copyright © 2011-2022 走看看