定义
模式引入
首先,什么是过滤器模式?这种模式生活中比较常见,比如移动推出某项优惠套餐,但是套餐可使用的用户群体有限,必须满足入网 5 年以上这种条件,我们可以将 “入网五年” 作为客户群体的过滤条件,这种就是简单的过滤器模式应用。
又比如,现在的垃圾分类,很多城市从上海开始,已经运行起来,着实让人头大,这种垃圾过滤分类的思想其实本身就是一种过滤模式。再比如我们设计日志系统时,并非所有日志都要收集,而是选择性过滤收集,这种实现了日志过滤的东西本身就是过滤器模式的一种体现。讲了这么多,到底什么是过滤器模式?
模式定义
过滤器模式(Filter Pattern)又称为标准模式 (Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过运算逻辑以解耦的方式将它们联系起来。这种类型的设计模式属于结构型模式,说白了,就是按条件筛选一组对象出来。
目的:使用不同标准来过滤一组对象
实现:制定不同的规则来实现过滤,然后对过滤结果进行分组
组成角色
过滤器模式一般有如下角色:
- 抽象过滤器角色(AbstractFilter):负责定义过滤器的实现接口,具体的实现还要具体过滤器角色去参与,客户端可以调用抽象过滤器角色中定义好的方法,将客户端的所有请求委派到具体的实现类去,从而让实现类去处理;
- ConcreteFilter(具体过滤器角色):该角色负责具体筛选规则的逻辑实现,最后再返回一个过滤后的数据集合,标准的过滤器只对数据做过滤,当然也可以对集合中的数据做某项处理,再将处理后的集合返回;
- Subject(被过滤的主体角色):一个软件系统中可以有一个或多个目标角色,在具体过滤器角色中会对指定感兴趣的目标进行处理,以确保后面的数据确实是我想要的
过滤器延伸 —— 管道和过滤器
这里的管道,其实比较好理解,就类似于一根根的水管或者一个个的流水线,将一个个的过滤器连接起来,形成一个过滤器链(过滤器链可以携带多个过滤器,并且可以以自定义顺序执行它们),原始数据经过一道道的加工工序,最后形成我们需要的数据或产品。一般情况下我们还存在一个过滤器管理器的角色,过滤器管理器负责管理过滤器和过滤器链。
应用场景
下面我们通过一个例子来了解下过滤器模式,我们就以垃圾分类为例进行说明,使用不同的垃圾桶进行垃圾分类过滤,“垃圾” 就是我们的被过滤的角色,垃圾桶可以充当我们的绝体过滤器角色,实例的类图如下:
首先是 “垃圾” 类,也就是我们的被过滤的主体角色:
public class Rubbish {
private String name; // 垃圾名称
private boolean isHarm; // 是否有害垃圾
private boolean isRecycled; // 是否可回收
private boolean isDry; // 是否干垃圾
private boolean isWet; // 是否湿垃圾
public Rubbish(String name, boolean isHarm, boolean isRecycled, boolean isDry, boolean isWet) {
this.name = name;
this.isHarm = isHarm;
this.isRecycled = isRecycled;
this.isDry = isDry;
this.isWet = isWet;
}
// ... getter、setter省略,或者直接使用lombok
}
然后是我们的过滤标准的接口,即抽象过滤器角色:
public interface Criteria {
// 定义过滤的标准
List<Rubbish> rubbishFilter(List<Rubbish> rubbishes);
}
我们继续创建实现了 Criteria 接口的几个实体类:
// 干垃圾
public class DryRubbishCriteria implements Criteria{
@Override
public List<Rubbish> rubbishFilter(List<Rubbish> rubbishes) {
List<Rubbish> rubbishList = new ArrayList<>();
for (Rubbish rubbish: rubbishes) {
// 这里只过滤出所有干垃圾
if (rubbish.isDry()) {
rubbishList.add(rubbish);
}
}
return rubbishList;
}
}
...
// 有害垃圾
public class HarmfulRubbishCriteria implements Criteria{
@Override
public List<Rubbish> rubbishFilter(List<Rubbish> rubbishes) {
List<Rubbish> rubbishList = new ArrayList<>();
for (Rubbish rubbish: rubbishes) {
// 这里只过滤出所有有害垃圾
if (rubbish.isHarm()) {
rubbishList.add(rubbish);
}
}
return rubbishList;
}
}
...
// 可回收垃圾
public class RecycledRubbishCriteria implements Criteria{
@Override
public List<Rubbish> rubbishFilter(List<Rubbish> rubbishes) {
List<Rubbish> rubbishList = new ArrayList<>();
for (Rubbish rubbish: rubbishes) {
// 这里只过滤出所有可回收垃圾
if (rubbish.isRecycled()) {
rubbishList.add(rubbish);
}
}
return rubbishList;
}
}
...
// 湿垃圾
public class WetRubbishCriteria implements Criteria{
@Override
public List<Rubbish> rubbishFilter(List<Rubbish> rubbishes) {
List<Rubbish> rubbishList = new ArrayList<>();
for (Rubbish rubbish: rubbishes) {
// 这里只过滤出所有湿垃圾
if (rubbish.isWet()) {
rubbishList.add(rubbish);
}
}
return rubbishList;
}
}
使用不同的标准(Criteria)来过滤 Rubbish 对象的列表:
public class Main {
public static void main(String[] args) {
// 原始数据集合
List<Rubbish> rubbishList = new ArrayList<>();
rubbishList.add(new Rubbish("果壳", false, false, true, false));
rubbishList.add(new Rubbish("陶瓷", false, false, true, false));
rubbishList.add(new Rubbish("菜根菜叶", false, false, false, true));
rubbishList.add(new Rubbish("果皮", false, false, false, true));
rubbishList.add(new Rubbish("水银温度计", true, false, false, false));
rubbishList.add(new Rubbish("电池", true, false, false, false));
rubbishList.add(new Rubbish("灯泡", true, false, false, false));
rubbishList.add(new Rubbish("废纸塑料", false, true, false, false));
rubbishList.add(new Rubbish("金属和布料", false, true, false, false));
rubbishList.add(new Rubbish("玻璃", false, true, false, false));
// 四种不同的过滤标准
Criteria dryRubbishCriteria = new DryRubbishCriteria();
Criteria wetRubbishCriteria = new WetRubbishCriteria();
Criteria harmfulRubbishCriteria = new HarmfulRubbishCriteria();
Criteria recycledRubbishCriteria = new RecycledRubbishCriteria();
System.out.println("干垃圾: ");
printRubbishes(dryRubbishCriteria.rubbishFilter(rubbishList));
System.out.println("湿垃圾: ");
printRubbishes(wetRubbishCriteria.rubbishFilter(rubbishList));
System.out.println("有害垃圾: ");
printRubbishes(harmfulRubbishCriteria.rubbishFilter(rubbishList));
System.out.println("可回收垃圾: ");
printRubbishes(recycledRubbishCriteria.rubbishFilter(rubbishList));
}
private static void printRubbishes(List<Rubbish> rubbishes) {
for (Rubbish rubbish: rubbishes) {
System.out.println(rubbish);
}
}
}
结果如下:
干垃圾:
Rubbish{name='果壳', isHarm=false, isRecycled=false, isDry=true, isWet=false}
Rubbish{name='陶瓷', isHarm=false, isRecycled=false, isDry=true, isWet=false}
湿垃圾:
Rubbish{name='菜根菜叶', isHarm=false, isRecycled=false, isDry=false, isWet=true}
Rubbish{name='果皮', isHarm=false, isRecycled=false, isDry=false, isWet=true}
有害垃圾:
Rubbish{name='水银温度计', isHarm=true, isRecycled=false, isDry=false, isWet=false}
Rubbish{name='电池', isHarm=true, isRecycled=false, isDry=false, isWet=false}
Rubbish{name='灯泡', isHarm=true, isRecycled=false, isDry=false, isWet=false}
可回收垃圾:
Rubbish{name='废纸塑料', isHarm=false, isRecycled=true, isDry=false, isWet=false}
Rubbish{name='金属和布料', isHarm=false, isRecycled=true, isDry=false, isWet=false}
Rubbish{name='玻璃', isHarm=false, isRecycled=true, isDry=false, isWet=false}
这样过滤器模式的简单应用就一目了然了吧
总结
总结下过滤器模式的特点:
- 可插拔:过滤器的设计概念要求其是支持可插拔设计的;
- 有序性:过滤器是被设计为一组组的过滤装置,要实现数据过滤,就必须有顺序性要求,比如我们要设计编解码过滤器,用户请求过来的 xml 数据会优先通过 xml2json 过滤器进行数据处理,完了再在响应发出前进行相应的 json2xml 过滤处理,以保证客户端交互以 xml 数据格式为准的同时系统内部数据交互还是维持 json 格式不变;
- 过滤器的独立性:每种过滤器必须是独立的实体,其状态不受其它过滤器的影响,每个过滤器都有自己独立的数据输入输出接口,只要各个过滤器之间传送的数据遵守共同的规约就可以相连接。