java设计模式分析之过滤器模式 、组合模式、外观模式

一个优秀的android开源框架中每每会体现出不少Java设计模式的影子,了解设计模式有助于理解开源框架中的程序设计之美接下来我会将本身整理的对一些设计模式的理解记录在这里html

若您对个人分享感兴趣能够访问:java设计模式专栏
java

本篇记录:过滤器模式 、组合模式、外观模式
android

传送门:  java设计模式分析及在android中的应用一
编程

参考:

java设计模式之组合模式windows

从真实项目中抠出来的设计模式:过滤器模式
设计模式


一、过滤器模式
介绍:

过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种结构型模式,这种模式容许开发人员使用不一样的标准来过滤一组对象,经过逻辑运算以解耦的方式把它们链接起来,它能够结合多个标准来得到单一标准安全

方法:架构

咱们能够定义一系列规则。这些规则能够针对目标进行知足自身规则的过滤框架

使用场景:ide

咱们在给用户作订单催付通知的时候,会有这样的一种场景,用户在系统后台设置一组能够催付的规则,好比说订单金额大于xx元,非黑名单用户,来自哪一个地区,已购买过某个商品等等这样的条件,若是这时用户下了一个订单,那程序要判断的就是看一下此订单是否知足这些规则中的某一个,若是知足,咱们给他发送催付通知,这种场景是不少作CRM的同窗都会遇到的问题,那针对这种场景,如何更好的规划业务逻辑呢?

若是是普通代码实现:

咱们可能会定义出一个删选类,由其负责对各类规则的筛选,那么不少不清楚设计模式的人可能会秀出以下代码:

var regulars = new List<Regulars>();

                 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则1", AnalysisConditons = "xxxx" });
                 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则2", AnalysisConditons = "xxxx" });
                 regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则3", AnalysisConditons = "xxxx" });
                regulars.Add(new Regulars() { RegularID = 1, RegularName = "规则4", AnalysisConditons = "xxxx" });
   
                 var filters = FilterRegularID(regulars);
                 filters = FilterRegularName(filters);
                 filters = FilterCondtions(filters);
                //... 后续逻辑
          }
                static List<Regulars> FilterRegularID(List<Regulars> persons){
                //过滤 “姓名” 的逻辑
                 return null;
            }

                 static List<Regulars> FilterRegularName(List<Regulars> persons) {
               //过滤 “age” 的逻辑
                return null;
            }

    /// <summary>
     /// 各类催付规则
  /// </summary>
}

    这种写法简单粗暴,维护起来也是同样的简单粗暴,上万行的代码就是这样出来的,暂时看来已经实现了必须的功能,可是一旦后续一旦有规则的变动,相信即使是当时写出这些代码的人也会头疼

设计模式告诉咱们一个简单的“开闭原则”,那就是追求最小化的修改代码,这种场景有更好的优化策略吗?

    固然有对应到设计模式上就是“过滤器模式”,专门针对这种场景的解决方案,一个维度一个类,而后经过逻辑运算类将他们进行组合

让咱们看看使用过滤器模式优化以后的代码结构:


    从上面这张图纸中能够看到,咱们抽象出了一个IFilter接口,而后提取成了三个子类每个子类负责一个维度的过滤方法,而后实现了两个逻辑运算类AND和OR子类Filter,用于动态的对上面的三个维度的过滤方法进行AND,OR逻辑运算

最后在咱们的调用程序里面,咱们须要作的工做就简单了,只须要将每一个维度的过滤条件,追加到逻辑运算类里面就能够说笑呢功能了

and和or逻辑运算类的实现也比较简单,两个类里面都维护了一个过滤器列表

  • and类只须要遍历全部的过滤器,剔除须要过滤的原始对象集合中不符合规则的对象就能够了
  • or类可使用一个hashMap,从须要过滤的原始对象集合中,选取符合某一个过滤条件的对象放入hashMap就能够了

使用泛型咱们能够增长对多种过滤对象的支持

有没有发现,若是后续有需求变动,好比说增长筛选的维度,我只须要新增一个继承IFilter的子类就搞定了,客户端在调用的时候只要在Filters集合中追加该筛选维度,是否是就OK了

因此这种模式几乎达到了无代码修改的地步,这就是设计模式给咱们带来的便捷


二、组合模式

可能咱们看到组合这个词,会下意识的和Java对象里面的对象的组合联系起来,但其实这二者之间没有联系

java对象的组合指的是对象之间的协同工做,例如:

    一我的能够由大脑、躯干、四肢等等对象组成那么在People这个类中将head、trunk、limb等做为字段组合进来,让这些对象协同完成一我的对象和以完成的工做,这就是java对象的组合

    而组合模式则主要是使用面向对象的思想来实现树形结构的构建与处理,其中心思想是把一组类似的对象当作一个单一对象来进行处理

举个例子:

windows系统中对于文件夹管理就是典型的组合模式对于树形结构的处理

再好比应用软件中的菜单,办公系统中的公司组织结构等等

组合模式的优势:

组合模式经过一种巧妙的设计方案使得用户能够一致性地处理整个树形结构或者树形结构的一部分,也能够一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点)

接下来咱们看看组合模式在实际场景中的应用

设计杀毒软件:

    该软件既能够对某个文件夹(Folder)杀毒,也能够对某个指定的文件(File)进行杀毒。该杀毒软件还能够根据各种文件的特色,为不一样类型的文件提供不一样的杀毒方式,例如图像文件(ImageFile)和文本文件(TextFile)的杀毒方式就有所差别。现须要提供该杀毒软件的总体框架设计方案。

     对于树形结构,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(能够是容器对象,也能够是叶子对象)并调用执行,牵一而动百,其中使用了递归调用的机制来对整个结构进行处理。

    因为容器对象和叶子对象在功能上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多数状况下咱们但愿一致地处理它们,由于对于这些对象的区别对待将会使得程序很是复杂。

    组合模式为解决此类问题而诞生,它可让叶子对象和容器对象的使用具备一致性

例如咱们对杀毒软件的架构设计以下:



AbstractFile充当抽象构件类,Folder充当容器构件类,ImageFile、TextFile和VideoFile充当叶子构件类

叶子类不支持文件的增删操做,可是由于要进行统一封装,保持对调用这的透明,因此也实现了增删操做,不过能够提供对应的错误提示和异常处理

    因为在本实例中使用了组合模式,在抽象构件类中声明了全部方法,包括用于管理和访问子构件的方法,如add()方法和remove()方法等,所以在ImageFile等叶子构件类中实现这些方法时必须进行相应的异常处理或错误提示

在容器构件类Folder类的killVirus()方法中,Folder将递归调用其成员对象的killVirus()方法,从而实现对整个树形结构的遍历。


若是须要更换操做节点,例如只需对文件夹“文本文件”进行杀毒,客户端代码只需进行简单的修改便可

客户端无须关心节点的层次结构,能够对所选节点进行统一处理,提升系统的灵活性


固然若是不想让叶子节点实现没必要要的方法,能够采用安全组合模式:



    安全组合模式的缺点是不够透明,由于叶子构件和容器构件具备不一样的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,所以客户端不能彻底针对抽象编程,必须有区别地对待叶子构件和容器构件

    在实际应用中,安全组合模式的使用频率也很是高,在Java AWT中使用的组合模式就是安全组合模式。


三、外观模式(retrofit)
外观模式(门面模式),这种模式隐藏了系统的复杂性,并向客户端提供了一个客户端能够访问系统的接口。来隐藏系统的复杂性
例如:图片加载框架Glide,咱们只须要使用其提供的简单的操做接口就能够完成复杂的功能,Glide用这种模式隐藏了其背后进行的大量工做
关键之处在于:
在客户端和复杂系统之间再加上一层,这一层将调用顺序,依赖关系等处理好这也就是Glide提供给咱们的接待员,这个接待员理解Glide在背后所作的各类工做,而隐藏了其中的复杂联系,只向咱们提供了简单的调用入口
缺点:
不符合开闭原则,若是想修改东西会比较麻烦,由于继承重写都不方便

原理图以下:

ShapeMaker就是外观模式提供的接待员,这个接待员熟悉左边复杂的shape系统的内部结构,而后隐藏了其中的各类实现,而仅仅只向咱们提供了简单那的调用方法 优势是:简单容易上手,而且比较安全 还有一个使用场景:在软件的各个层次结构中,可使用外观模式定义系统中的每一层的入口