过滤器模式(Filter Pattern)


过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。

实现

我将创建一个 Person 对象、Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列表。Main,我的演示类使用 Criteria 对象,基于各种标准和它们的结合来过滤 Person 对象的列表。

步骤 1:创建一个类,在该类上应用标准。

Person.java

package com.dao.pattern.filter.vo;
    
    import java.io.Serializable;
    
    /**
     * 人,用于制作标准
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.vo.Person.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 09:39:00
     */
    public class Person implements Serializable{
    
    
        private static final long serialVersionUID = 7131437071202512187L;
        /**
         * 姓名
         */
        private String name;
    
        /**
         * 国家
         */
        private String country;
    
        /**
         * 肤色
         */
        private String skin;
    
    
        public Person(String name, String country, String skin) {
            this.name = name;
            this.country = country;
            this.skin = skin;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getCountry() {
            return country;
        }
    
        public void setCountry(String country) {
            this.country = country;
        }
    
        public String getSkin() {
            return skin;
        }
    
        public void setSkin(String skin) {
            this.skin = skin;
        }
    }

步骤 2:为标准(Criteria)创建一个接口。

Criteria.java

package com.dao.pattern.filter.interfaces;
    
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.List;
    
    /**
     * 条件接口
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.interfaces.Criteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 09:39:00
     */
    public interface Criteria {
    
       /**
        * 条件处理
        *
        * @author 阿导
        * @time 2018/3/22
        * @CopyRight 万物皆导
        * @param persons
        * @return java.util.List<com.dao.pattern.filter.vo.Person>
        */
       List<Person> meetCriteria(List<Person> persons);
    }

步骤 3:创建实现了 Criteria 接口的实体类。

ChinaCriteria.java

package com.dao.pattern.filter.impl;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 中国人
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.impl.ChinaCriteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 10:17:00
     */
    public class ChinaCriteria implements Criteria {
    
        /**
         * 条件处理(中国人)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //声明结果集
            List<Person> personList=new ArrayList<Person>();
            //判断集合不为空
            if(!persons.isEmpty()){
                //遍历,过滤
                persons.stream().filter(person->"中国".equalsIgnoreCase(person.getCountry())).forEach(person->personList.add(person));
            }
    
            return personList;
        }
    }

AmericaCriteria.java

package com.dao.pattern.filter.impl;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 美国人
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.impl.AmericaCriteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 10:22:00
     */
    public class AmericaCriteria implements Criteria {
    
        /**
         * 条件处理(美国人)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //声明结果集
            List<Person> personList=new ArrayList<Person>();
            //判断集合不为空
            if(!persons.isEmpty()){
                //遍历,过滤
                persons.stream().filter(person->"美国".equalsIgnoreCase(person.getCountry())).forEach(person->personList.add(person));
            }
    
            return personList;
        }
    }

YellowCriteria.java

package com.dao.pattern.filter.impl;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 黄种人
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.impl.YellowCriteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 10:31:00
     */
    public class YellowCriteria implements Criteria {
    
        /**
         * 条件处理(黄种人)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //声明结果集
            List<Person> personList=new ArrayList<Person>();
            //判断集合不为空
            if(!persons.isEmpty()){
                //遍历,过滤
                persons.stream().filter(person->"黄色".equalsIgnoreCase(person.getSkin())).forEach(person->personList.add(person));
            }
    
            return personList;
        }
    }

WhiteCriteria.java

package com.dao.pattern.filter.impl;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 白种人
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.impl.WhiteCriteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 10:32:00
     */
    public class WhiteCriteria implements Criteria {
    
        /**
         * 条件处理(白种人)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //声明结果集
            List<Person> personList=new ArrayList<Person>();
            //判断集合不为空
            if(!persons.isEmpty()){
                //遍历,过滤
                persons.stream().filter(person->"白色".equalsIgnoreCase(person.getSkin())).forEach(person->personList.add(person));
            }
    
            return personList;
        }
    }

步骤 4:配合一些逻辑运算实现 Criteria 接口的实体类。

AndCriteria.java

package com.dao.pattern.filter.core;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    /**
     * 且关系
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.core.AndCriateria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 10:35:00
     */
    public class AndCriteria implements Criteria{
    
        /**
         * 第一个条件
         */
        private Criteria criteria;
    
        /**
         * 第二个条件
         */
        private Criteria otherCriteria;
    
        /**
         * 构造方法
         *
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         * @param criteria
         * @param otherCriteria
         * @return
         */
        public AndCriteria(Criteria criteria, Criteria otherCriteria) {
            this.criteria = criteria;
            this.otherCriteria = otherCriteria;
        }
    
        /**
         * 条件处理(并且关系)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //声明结果集
            List<Person> list=new ArrayList<Person>();
            //获取两个条件的结果
            List<Person> personFirst = criteria.meetCriteria(persons);
            List<Person> personSecond = otherCriteria.meetCriteria(persons);
    
            //若未空,交集肯定是空
            if(personFirst.isEmpty()){
                return new ArrayList<>();
            }
            //遍历取交集
            personFirst.stream().filter(person ->personSecond.contains(person)).forEach(person ->list.add(person));
            //返回结果
            return list;
        }
    }

OrCriteria.java

package com.dao.pattern.filter.core;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    /**
     * 或关系
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.core.OrCriteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 10:34:00
     */
    public class OrCriteria implements Criteria {
        /**
         * 第一个条件
         */
        private Criteria criteria;
    
        /**
         * 第二个条件
         */
        private Criteria otherCriteria;
    
        /**
         * 构造方法
         *
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         * @param criteria
         * @param otherCriteria
         * @return
         */
        public OrCriteria(Criteria criteria, Criteria otherCriteria) {
            this.criteria = criteria;
            this.otherCriteria = otherCriteria;
        }
    
        /**
         * 条件处理(或者关系)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //获取第一个条件结果【另一边已经做了空处理】
            Set<Person> personSet =new HashSet<>(criteria.meetCriteria(persons));
            //添加第二个集合【已做空处理】
            personSet.addAll(otherCriteria.meetCriteria(persons));
    
            return new ArrayList<Person>(personSet.isEmpty()?new ArrayList<Person>():personSet);
        }
    }

ContraryCriteria.java

package com.dao.pattern.filter.core;
    
    import com.dao.pattern.filter.interfaces.Criteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 相反的
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.core.ContraryCriteria.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 12:49:00
     */
    public class ContraryCriteria implements Criteria {
    
        /**
         * 条件
         */
        private Criteria criteria;
    
    
        /**
         * 构造方法
         *
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         * @param criteria
         * @return
         */
        public ContraryCriteria(Criteria criteria) {
            this.criteria = criteria;
        }
    
        /**
         * 条件处理(非关系)
         *
         * @param persons
         * @return java.util.List<com.dao.pattern.filter.vo.Person>
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         */
        @Override
        public List<Person> meetCriteria(List<Person> persons) {
            //复制一份
            List<Person> list=new ArrayList<>(persons);
            //取结果
            List<Person> personList = criteria.meetCriteria(persons);
            //取非情况
            list.removeAll(personList);
            //返回结果
            return list;
        }
    }

步骤 5:使用不同的标准(Criteria)和它们的结合来过滤 Person 对象的列表。

Main.java

package com.dao.pattern.filter.main;
    
    import com.alibaba.fastjson.JSON;
    import com.dao.pattern.filter.core.AndCriteria;
    import com.dao.pattern.filter.core.ContraryCriteria;
    import com.dao.pattern.filter.core.OrCriteria;
    import com.dao.pattern.filter.impl.AmericaCriteria;
    import com.dao.pattern.filter.impl.ChinaCriteria;
    import com.dao.pattern.filter.impl.WhiteCriteria;
    import com.dao.pattern.filter.impl.YellowCriteria;
    import com.dao.pattern.filter.vo.Person;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 抓方法入口
     *
     * @author 阿导
     * @version 1.0
     * @fileName com.dao.pattern.filter.main.Main.java
     * @CopyRright (c) 2018-万物皆导
     * @created 2018-03-22 15:22:00
     */
    public class Main {
        /**
         * 主方法入口
         *
         * @author 阿导
         * @time 2018/3/22
         * @CopyRight 万物皆导
         * @param args
         * @return void
         */
        public static void main(String[] args){
            //声明一下
            List<Person> persons=new ArrayList<Person>();
            //添加一些人物信息
            persons.add(new Person("孙中山","中国","黄色"));
            persons.add(new Person("张柏芝","中国","白色"));
            persons.add(new Person("比尔盖茨","美国","白色"));
            persons.add(new Person("奥巴马","美国","黑色"));
            persons.add(new Person("神秘人","美国","黄色"));
    
            //美国人
            List<Person> personAmerica = new AmericaCriteria().meetCriteria(persons);
            System.out.println("美国人:"+ JSON.toJSONString(personAmerica));
            //中国人
            List<Person> personChina = new ChinaCriteria().meetCriteria(persons);
            System.out.println("黄种人:"+ JSON.toJSONString(personChina));
    
            //黄种人
            List<Person> personYellow = new YellowCriteria().meetCriteria(persons);
            System.out.println("黄种人:"+ JSON.toJSONString(personYellow));
    
            //白种人
            List<Person> personWhite = new WhiteCriteria().meetCriteria(persons);
            System.out.println("白种人:"+ JSON.toJSONString(personWhite));
    
            //~黄种人
            List<Person> personContraryYellow = new ContraryCriteria(new YellowCriteria()).meetCriteria(persons);
            System.out.println("非黄种人:"+ JSON.toJSONString(personContraryYellow));
    
            //白种人&美国人
            List<Person> personWhiteAndAmerica = new AndCriteria(new WhiteCriteria(), new AmericaCriteria()).meetCriteria(persons);
            System.out.println("白种人并且美国人:"+ JSON.toJSONString(personWhiteAndAmerica));
    
            //白种人||美国人
            List<Person> personWhiteOrAmerica = new OrCriteria(new WhiteCriteria(), new AmericaCriteria()).meetCriteria(persons);
            System.out.println("白种人或者美国人:"+ JSON.toJSONString(personWhiteOrAmerica));
    
        }
    
    }

步骤 6:验证输出。

美国人:[{"country":"美国","name":"比尔盖茨","skin":"白色"},{"country":"美国","name":"奥巴马","skin":"黑色"},{"country":"美国","name":"神秘人","skin":"黄色"}]
    黄种人:[{"country":"中国","name":"孙中山","skin":"黄色"},{"country":"中国","name":"张柏芝","skin":"白色"}]
    黄种人:[{"country":"中国","name":"孙中山","skin":"黄色"},{"country":"美国","name":"神秘人","skin":"黄色"}]
    白种人:[{"country":"中国","name":"张柏芝","skin":"白色"},{"country":"美国","name":"比尔盖茨","skin":"白色"}]
    非黄种人:[{"country":"中国","name":"张柏芝","skin":"白色"},{"country":"美国","name":"比尔盖茨","skin":"白色"},{"country":"美国","name":"奥巴马","skin":"黑色"}]
    白种人并且美国人:[{"country":"美国","name":"比尔盖茨","skin":"白色"}]
    白种人或者美国人:[{"country":"美国","name":"比尔盖茨","skin":"白色"},{"country":"中国","name":"张柏芝","skin":"白色"},{"country":"美国","name":"奥巴马","skin":"黑色"},{"country":"美国","name":"神秘人","skin":"黄色"}]