• 每天一个设计模式之过滤器模式(Filter/Criteria Pattern)


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

    一、UML类图

    在这里插入图片描述

    二、代码示例

    过滤器接口,和一些逻辑组合的接口实现类

    package filter;
    
    public interface Criteria<T> {
        boolean matches(T candidate);
    
        // 只有default方法才可以有方法体
        default Criteria<T> and(Criteria<T> other) {
            return new AndCriteria<T>(this, other);
        }
    
        // 只有default方法才可以有方法体
        default Criteria<T> or(Criteria<T> other) {
            return new OrCriteria<T>(this, other);
        }
    
        class AndCriteria<T> implements Criteria<T> {
            private Criteria<T> thisCriteria, thatCriteria;
    
            public AndCriteria(Criteria<T> thisCriteria, Criteria<T> thatCriteria) {
                this.thisCriteria = thisCriteria;
                this.thatCriteria = thatCriteria;
            }
    
            @Override
            public boolean matches(T candidate) {
                return thisCriteria.matches(candidate) && thatCriteria.matches(candidate);
            }
        }
    
        class OrCriteria<T> implements Criteria<T> {
            private Criteria<T> thisCriteria, thatCriteria;
    
            public OrCriteria(Criteria<T> thisCriteria, Criteria<T> thatCriteria) {
                this.thisCriteria = thisCriteria;
                this.thatCriteria = thatCriteria;
            }
    
            @Override
            public boolean matches(T candidate) {
                return thisCriteria.matches(candidate) || thatCriteria.matches(candidate);
            }
        }
    
        class NotCriteria<T> implements Criteria<T> {
            private Criteria<T> thisCriteria;
    
            public NotCriteria(Criteria<T> thisCriteria) {
                this.thisCriteria = thisCriteria;
            }
    
            @Override
            public boolean matches(T candidate) {
                return !thisCriteria.matches(candidate);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    具体的过滤器实现类

    public class MaleCriteria implements Criteria<Person> {
    
        @Override
        public boolean matches(Person candidate) {
            return candidate.getGender().equalsIgnoreCase("male");
        }
    }
    public class FemaleCriteria implements Criteria<Person> {
    
        @Override
        public boolean matches(Person candidate) {
            return candidate.getGender().equalsIgnoreCase("female");
        }
    }
    
    public class AdultCriteria implements Criteria<Person> {
    
        @Override
        public boolean matches(Person candidate) {
            return candidate.getAge() >= 18;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    被过滤对象

    package filter;
    
    public class Person {
        private String name, gender;
        private int age;
    
        public Person(String name, String gender, int age) {
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", gender='" + gender + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    客户类

    package filter;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    import java.util.stream.Collectors;
    
    public class Client {
        public static void main(String[] args) {
            List<Person> persons = Arrays.asList(
                    new Person("Zhang", "female", 28),
                    new Person("Wang", "male", 17),
                    new Person("Li", "female", 19),
                    new Person("Sun", "male", 22),
                    new Person("Han", "female", 16)
            );
            System.out.println("******************** old school ********************\n");
            System.out.println("all male people --->>>");
            System.out.println(persons.stream().filter(p -> new MaleCriteria().matches(p)).collect(Collectors.toList()) + "\n");
    
            System.out.println("all male and adult female people --->>>");
            System.out.println(persons.stream().filter(p -> new MaleCriteria().or(new AdultCriteria().and(new FemaleCriteria())).matches(p)).collect(Collectors.toList()) + "\n");
    
            System.out.println("******************** new style with Predicate ********************\n");
            // 完全不需要写那么多鸡肋的Criteria,在Java 8中完全可用Predicate来替代
            Predicate<Person> isMale = p -> p.getGender().equalsIgnoreCase("male");
            Predicate<Person> isFemale = p -> p.getGender().equalsIgnoreCase("female");
            Predicate<Person> isAdult = p -> p.getAge() >= 18;
            System.out.println(persons.stream().filter(isMale).collect(Collectors.toList()));
            System.out.println(persons.stream().filter(isMale.or(isFemale.and(isAdult))).collect(Collectors.toList()));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    测试结果

    ******************** old school ********************
    
    all male people --->>>
    [Person{name='Wang', gender='male', age=17}, Person{name='Sun', gender='male', age=22}]
    
    all male and adult female people --->>>
    [Person{name='Zhang', gender='female', age=28}, Person{name='Wang', gender='male', age=17}, Person{name='Li', gender='female', age=19}, Person{name='Sun', gender='male', age=22}]
    
    ******************** new style with Predicate ********************
    
    [Person{name='Wang', gender='male', age=17}, Person{name='Sun', gender='male', age=22}]
    [Person{name='Zhang', gender='female', age=28}, Person{name='Wang', gender='male', age=17}, Person{name='Li', gender='female', age=19}, Person{name='Sun', gender='male', age=22}]
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    【参考】

    1. https://www.geeksforgeeks.org/filter-pattern-in-java/
    2. https://www.linkedin.com/pulse/think-functional-rethinking-criteria-pattern-lambdas-sujit-kamthe/
    3. https://www.runoob.com/design-pattern/filter-pattern.html
  • 相关阅读:
    绘制文字(QFont字体)
    【案例】animation动画曲线之steps的使用
    pytest框架中的pytest.ini配置文件
    基于FPGA的图像RGB转HLS实现,包含testbench和MATLAB辅助验证程序
    Vue---keep-alive组件的使用,缓存组件
    node进程管理工具 pm2 常用操作命令
    and ,or,not operators,逻辑运算符,and>or,and优先评估
    day12:MyBatis的Dao层实现方式
    SAP ABAP OData 服务的分页加载数据集的实现(Paging)试读版
    3种等待方式,让你学会Selenium设置自动化等待测试脚本!
  • 原文地址:https://blog.csdn.net/M_sdn/article/details/126329356