在Java中使用过滤器设计模式


让我们讨论另一个非常有用的设计模式-过滤器设计模式。

过滤器设计模式

  • 该过滤器设计模式也被称为标准设计模式。
  • 该过滤器的设计模式是一种设计模式,它允许开发人员使用不同的标准/过滤条件和在通过逻辑运算去耦的方式链接它们来过滤一组对象。
  • 该过滤器的设计模式是一种结构模式可联合多个条件,以获得单个的标准。
  • 通过在Java 8中使用Lambda表达式,即使没有将其视为设计模式,使用起来也非常简单。但是,如果我们知道过滤的概念,我们将对代码的实现有更好的了解和掌握。
  • 有两种不同的创建过滤器的方式
    • 筛选整个集合。
    • 筛选集合的单个成员。
  • 在本文下面,我还将尝试着重强调使用lambda进行过滤。但是本文与Java Lambda表达式无关。根据观众的回应,我可能还会写另一篇文章来介绍lambda的基础知识。

filterdesignpattern.png

为了直接了解对象集合上的过滤模式,让我们使用在《Builder Design Pattern》一文中使用的Employee类。完全不需要使用构建器进行过滤。我们需要的只是一组要过滤的对象。我只是为了节省一些时间来编写一个好的POJO类以进行收集并做一些很好的过滤示例。希望你能理解。

使用筛选器设计模式的员工收集筛选器 这是Employee类的代码:

package org.trishinfotech.filter;
public class Employee {

    private int empNo;
    private String name;
    private Gender gender;
    private Deptt depttName;
    private int salary;
    private int mgrEmpNo;
    private String projectName;

    public Employee(EmployeeBuilder employeeBuilder) {
        if (employeeBuilder == null) {
            throw new IllegalArgumentException("Please provide employee builder to build employee object.");
        }
        if (employeeBuilder.empNo <= 0) {
            throw new IllegalArgumentException("Please provide valid employee number.");
        }
        if (employeeBuilder.name == null || employeeBuilder.name.trim().isEmpty()) {
            throw new IllegalArgumentException("Please provide employee name.");
        }
        this.empNo = employeeBuilder.empNo;
        this.name = employeeBuilder.name;
        this.gender = employeeBuilder.gender;
        this.depttName = employeeBuilder.depttName;
        this.salary = employeeBuilder.salary;
        this.mgrEmpNo = employeeBuilder.mgrEmpNo;
        this.projectName = employeeBuilder.projectName;
    }

    public int getEmpNo() {
        return empNo;
    }

    public String getName() {
        return name;
    }

    public Gender getGender() {
        return gender;
    }

    public Deptt getDepttName() {
        return depttName;
    }

    public int getSalary() {
        return salary;
    }

    public int getMgrEmpNo() {
        return mgrEmpNo;
    }

    public String getProjectName() {
        return projectName;
    }

    @Override
    public String toString() {
        // StringBuilder class also uses Builder Design Pattern with implementation of
        // java.lang.Appendable interface
        StringBuilder builder = new StringBuilder();
        builder.append("Employee [empNo=").append(empNo).append(", name=").append(name).append(", gender=")
                .append(gender).append(", depttName=").append(depttName).append(", salary=").append(salary)
                .append(", mgrEmpNo=").append(mgrEmpNo).append(", projectName=").append(projectName).append("]");
        return builder.toString();
    }

    public static class EmployeeBuilder {
        private int empNo;
        protected String name;
        protected Gender gender;
        protected Deptt depttName;
        protected int salary;
        protected int mgrEmpNo;
        protected String projectName;

        public EmployeeBuilder() {
            super();
        }

        public EmployeeBuilder empNo(int empNo) {
            this.empNo = empNo;
            return this;
        }

        public EmployeeBuilder name(String name) {
            this.name = name;
            return this;
        }

        public EmployeeBuilder gender(Gender gender) {
            this.gender = gender;
            return this;
        }

        public EmployeeBuilder depttName(Deptt depttName) {
            this.depttName = depttName;
            return this;
        }
        public EmployeeBuilder salary(int salary) {
            this.salary = salary;
            return this;
        }

        public EmployeeBuilder mgrEmpNo(int mgrEmpNo) {
            this.mgrEmpNo = mgrEmpNo;
            return this;
        }

        public EmployeeBuilder projectName(String projectName) {
            this.projectName = projectName;
            return this;
        }

        public Employee build() {
            Employee emp = null;
            if (validateEmployee()) {
                emp = new Employee(this);
            } else {
                System.out.println("Sorry! Employee objects can't be build without required details");
            }
            return emp;
        }
        private boolean validateEmployee() {
            return (empNo > 0 && name != null && !name.trim().isEmpty());
        }
    }
}

我添加了 性别字段,还将depttName更改为枚举,以清楚地编写过滤条件。因此,我们还要定义枚举。

这是性别枚举的代码:

package org.trishinfotech.filter;
public enum Gender {
    MALE, FEMALE;
}

这是Deptt枚举的代码:

package org.trishinfotech.filter;
public enum Deptt {
    ENG, QA, HR, SUPPORT, IT, ADMIN 
}

示例1:通过使用筛选器为整个集合 这样,我们接受整个集合,并通过消除根据过滤条件不适用的成员来返回集合。

现在,让我们编写一个名为Filter 的接口来实现不同的过滤条件或条件:

package org.trishinfotech.filter;
import java.util.List;
public interface Filter {
    public List<Employee> apply(List<Employee> employees);
}

这是MaleFilter类的代码:

package org.trishinfotech.filter.example1;
import java.util.ArrayList;
import java.util.List;
import org.trishinfotech.filter.Employee;
import org.trishinfotech.filter.Gender;
public class MaleFilter implements Filter {

    @Override
    public List<Employee> apply(List<Employee> employees) {
        // implementing in old way
        List<Employee> filteredEmployees = new ArrayList<Employee>();
        if (employees != null) {
            for (Employee employee : employees) {
                if (Gender.MALE.equals(employee.getGender())) {
                    filteredEmployees.add(employee);
                }
            }
        }
        return filteredEmployees;
    }

}

这是EngFilter类的代码:

package org.trishinfotech.filter.example1;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.trishinfotech.filter.Deptt;
import org.trishinfotech.filter.Employee;
public class EngFilter implements Filter {
    @Override
    public List<Employee> apply(List<Employee> employees) {
        List<Employee> filteredEmployees = new ArrayList<Employee>();
        // implementing using lambda expressions
        if (employees != null) {
            filteredEmployees.addAll(employees.stream().filter(employee -> Deptt.ENG.equals(employee.getDepttName()))
                    .collect(Collectors.toList()));
        }
        return filteredEmployees;
    }

}

让我们再写两个过滤器,以通过' And Condition'或' Or Condition'组合任何两个过滤器。

这是AndFilter类的代码:

package org.trishinfotech.filter.example1;
import java.util.List;
import org.trishinfotech.filter.Employee;
public class AndFilter implements Filter {
    private Filter filter;
    private Filter anotherFilter;
    public AndFilter(Filter filter, Filter anotherFilter) {
        this.filter = filter;
        this.anotherFilter = anotherFilter;
    }
    @Override
    public List<Employee> apply(List<Employee> employees) {
        List<Employee> firstFilteredEmployees = filter.apply(employees);
        List<Employee> secondFilterEmployees = anotherFilter.apply(firstFilteredEmployees);
        return secondFilterEmployees;
    }

}

这是OrFilter类的代码:

package org.trishinfotech.filter.example1;
import java.util.ArrayList;
import java.util.List;
import org.trishinfotech.filter.Employee;
public class OrFilter implements Filter {
    private Filter filter;
    private Filter anotherFilter;
    public OrFilter(Filter Filter, Filter anotherFilter) {
        this.filter = Filter;
        this.anotherFilter = anotherFilter;
    }
    @Override
    public List<Employee> apply(List<Employee> employees) {
        List<Employee> firstFilteredEmployees = filter.apply(employees);
        List<Employee> secondFilterEmployees = anotherFilter.apply(firstFilteredEmployees);
        // now lets make or Filter.
        // first copy all first Filter filtered employees.
        // now add all second Filter filtered employees which are NOT already in the list
        // via first Filter employees.
        List<Employee> orFilteredEmployees = new ArrayList<Employee>(firstFilteredEmployees);
        secondFilterEmployees.removeAll(firstFilteredEmployees);
        orFilteredEmployees.addAll(secondFilterEmployees);
        return orFilteredEmployees;
    }

}

现在让我们编写Main 类来执行和测试输出:

package org.trishinfotech.filter.example1;
import java.util.Arrays;
import java.util.List;
import org.trishinfotech.filter.Deptt;
import org.trishinfotech.filter.Employee;
import org.trishinfotech.filter.Gender;
public class Main {
    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
                new Employee.EmployeeBuilder().empNo(101).name("Brijesh").gender(Gender.MALE).depttName(Deptt.ENG
                       .salary(140000).projectName("Builder Pattern").build(),
                new Employee.EmployeeBuilder().empNo(102).name("Racheal").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(90000).projectName("Factory Pattern").build(),
                new Employee.EmployeeBuilder().empNo(103).name("Kim").gender(Gender.MALE).depttName(Deptt.HR)
                        .salary(150000).projectName("Editorial").build(),
                new Employee.EmployeeBuilder().empNo(104).name("Micheal").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(80000).projectName("Decorator Pattern").build(),
                new Employee.EmployeeBuilder().empNo(105).name("Martin").gender(Gender.MALE).depttName(Deptt.SUPPORT)
                        .salary(65000).projectName("Web Management").build(),
                new Employee.EmployeeBuilder().empNo(106).name("Pierce").gender(Gender.MALE).depttName(Deptt.HR)
                        .salary(130000).projectName("Audit").build(),
                new Employee.EmployeeBuilder().empNo(107).name("Anjali").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(60000).projectName("State Pattern").build(),
                new Employee.EmployeeBuilder().empNo(108).name("Angelina").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(70000).projectName("Flyweight Pattern").build(),
                new Employee.EmployeeBuilder().empNo(109).name("Hemant").gender(Gender.MALE).depttName(Deptt.HR)
                        .salary(170000).projectName("Audit").build(),
                new Employee.EmployeeBuilder().empNo(110).name("Mike").gender(Gender.MALE).depttName(Deptt.IT)
                        .salary(150000).projectName("Networking").build());

        System.out.println("Print all employees...");
        printEmployees(employees);
        List<Employee> maleEmployees = (new MaleFilter().apply(employees));
        System.out.println("Print all Male employees...");
        printEmployees(maleEmployees);
        List<Employee> maleEngEmployees = (new AndFilter(new MaleFilter(), new EngFilter()).apply(employees));
        System.out.println("Print all Male And ENG employees...");
        printEmployees(maleEngEmployees);
    }

    private static void printEmployees(List<Employee> employees) {
        System.out.println("======================================================================");
        employees.stream().forEach(employee -> System.out.println(employee));
        System.out.println("======================================================================");
    }
}

以下是输出:

Print all employees...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
Employee [empNo=102, name=Racheal, gender=FEMALE, depttName=ENG, salary=90000, mgrEmpNo=0, projectName=Factory Pattern]
Employee [empNo=103, name=Kim, gender=MALE, depttName=HR, salary=150000, mgrEmpNo=0, projectName=Editorial]
Employee [empNo=104, name=Micheal, gender=FEMALE, depttName=ENG, salary=80000, mgrEmpNo=0, projectName=Decorator Pattern]
Employee [empNo=105, name=Martin, gender=MALE, depttName=SUPPORT, salary=65000, mgrEmpNo=0, projectName=Web Management]
Employee [empNo=106, name=Pierce, gender=MALE, depttName=HR, salary=130000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=107, name=Anjali, gender=FEMALE, depttName=ENG, salary=60000, mgrEmpNo=0, projectName=State Pattern]
Employee [empNo=108, name=Angelina, gender=FEMALE, depttName=ENG, salary=70000, mgrEmpNo=0, projectName=Flyweight Pattern]
Employee [empNo=109, name=Hemant, gender=MALE, depttName=HR, salary=170000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=110, name=Mike, gender=MALE, depttName=IT, salary=150000, mgrEmpNo=0, projectName=Networking]
======================================================================
Print all Male employees...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
Employee [empNo=103, name=Kim, gender=MALE, depttName=HR, salary=150000, mgrEmpNo=0, projectName=Editorial]
Employee [empNo=105, name=Martin, gender=MALE, depttName=SUPPORT, salary=65000, mgrEmpNo=0, projectName=Web Management]
Employee [empNo=106, name=Pierce, gender=MALE, depttName=HR, salary=130000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=109, name=Hemant, gender=MALE, depttName=HR, salary=170000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=110, name=Mike, gender=MALE, depttName=IT, salary=150000, mgrEmpNo=0, projectName=Networking]
======================================================================
Print all Male And ENG employees...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
======================================================================

示例2:通过使用筛选器为集合的单个成员 通过这种方式,我们在过滤器中接受集合的成员,并对其进行验证以了解该成员是否满足过滤器条件或条件。

这是Filter接口的代码:

package org.trishinfotech.filter.example2;
import org.trishinfotech.filter.Employee;
public interface Filter {
    public boolean apply(Employee employees);
}

这是MaleFilter类的代码:

package org.trishinfotech.filter.example2;
import org.trishinfotech.filter.Employee;
import org.trishinfotech.filter.Gender;
public class MaleFilter implements Filter {

    @Override
    public boolean apply(Employee employee) {
        return (employee != null && Gender.MALE.equals(employee.getGender()));
    }

}

这是MinSalaryFilter类的代码:

package org.trishinfotech.filter.example2;
import org.trishinfotech.filter.Employee;
public class MinSalaryFilter implements Filter {

    private int minSalary;

    public MinSalaryFilter(int minSalary) {
        super();
        this.minSalary = minSalary;
    }

    @Override
    public boolean apply(Employee employee) {
        return (employee != null && employee.getSalary() >= minSalary);
    }

}

同样,这是forFilter类的:

package org.trishinfotech.filter.example2;
import org.trishinfotech.filter.Employee;
public class AndFilter implements Filter {

    private Filter filter;
    private Filter anotherFilter;

    public AndFilter(Filter filter, Filter anotherFilter) {
        this.filter = filter;
        this.anotherFilter = anotherFilter;
    }
    @Override
    public boolean apply(Employee employee) {
        boolean firstFilter = filter.apply(employee);
        boolean secondFilter = anotherFilter.apply(employee);
        return firstFilter && secondFilter;
    }

}

这是OrFilter类的代码:

package org.trishinfotech.filter.example2;
import org.trishinfotech.filter.Employee;
public class OrFilter implements Filter {
    private Filter filter;
    private Filter anotherFilter;
    public OrFilter(Filter Filter, Filter anotherFilter) {
        this.filter = Filter;
        this.anotherFilter = anotherFilter;
    }

    @Override
    public boolean apply(Employee employee) {
        boolean firstFilter = filter.apply(employee);
        boolean secondFilter = anotherFilter.apply(employee);
        return firstFilter || secondFilter;
    }

}

更简单!是的,这是因为遍历集合已移至客户端应用程序(本例中为Main类)

现在,让我们编写Main 类来执行和测试输出:

package org.trishinfotech.filter.example2;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.trishinfotech.filter.Deptt;
import org.trishinfotech.filter.Employee;
import org.trishinfotech.filter.Gender;

public class Main {

    public static void main(String[] args) {
        List<Employee> employees = Arrays.asList(
                new Employee.EmployeeBuilder().empNo(101).name("Brijesh").gender(Gender.MALE).depttName(Deptt.ENG)
                        .salary(140000).projectName("Builder Pattern").build(),
                new Employee.EmployeeBuilder().empNo(102).name("Racheal").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(90000).projectName("Factory Pattern").build(),
                new Employee.EmployeeBuilder().empNo(103).name("Kim").gender(Gender.MALE).depttName(Deptt.HR)
                        .salary(150000).projectName("Editorial").build(),
                new Employee.EmployeeBuilder().empNo(104).name("Micheal").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(80000).projectName("Decorator Pattern").build(),
                new Employee.EmployeeBuilder().empNo(105).name("Martin").gender(Gender.MALE).depttName(Deptt.SUPPORT)
                        .salary(65000).projectName("Web Management").build(),
                new Employee.EmployeeBuilder().empNo(106).name("Pierce").gender(Gender.MALE).depttName(Deptt.HR)
                        .salary(130000).projectName("Audit").build(),
                new Employee.EmployeeBuilder().empNo(107).name("Anjali").gender(Gender.FEMALE).depttName(Deptt.ENG)

                        .salary(60000).projectName("State Pattern").build(),
                new Employee.EmployeeBuilder().empNo(108).name("Angelina").gender(Gender.FEMALE).depttName(Deptt.ENG)
                        .salary(70000).projectName("Flyweight Pattern").build(),
                new Employee.EmployeeBuilder().empNo(109).name("Hemant").gender(Gender.MALE).depttName(Deptt.HR)
                        .salary(170000).projectName("Audit").build(),
                new Employee.EmployeeBuilder().empNo(110).name("Mike").gender(Gender.MALE).depttName(Deptt.IT)
                        .salary(150000).projectName("Networking").build());
        System.out.println("Print all employees...");
        printEmployees(employees);
        List<Employee> maleEmployees = applyFilter(new MaleFilter(), employees);
       System.out.println("Print all Male employees...");
        printEmployees(maleEmployees);
        List<Employee> maleEngEmployees = applyFilter(new AndFilter(new MaleFilter(), new MinSalaryFilter(140000)), employees);
        System.out.println("Print all Male And Min Salary 140000 employees...");
        printEmployees(maleEngEmployees);
        // now lets try the same with the help of Java Lambda Expressions...
        System.out.println("\n\n\nnow lets try the same with the help of Java Lambda Expressions...");
        List<Employee> maleEmployeesUsingLambda = employees.stream()
                .filter(employee -> Gender.MALE.equals(employee.getGender())).collect(Collectors.toList());
        System.out.println("Print all Male employees using lambda...");
        printEmployees(maleEmployeesUsingLambda);
        List<Employee> maleEngEmployeesUsingLambda = employees.stream()
                .filter(employee -> Gender.MALE.equals(employee.getGender()))
               .filter(employee -> Deptt.ENG.equals(employee.getDepttName())).collect(Collectors.toList());
        System.out.println("Print all Male And ENG employees using lambda...");
        printEmployees(maleEngEmployeesUsingLambda);
    }

    private static List<Employee> applyFilter(Filter filter, List<Employee> employees) {
        return employees.stream().filter(employee -> filter.apply(employee)).collect(Collectors.toList());
    }

    private static void printEmployees(List<Employee> employees) {
        System.out.println("======================================================================");
        employees.stream().forEach(employee -> System.out.println(employee));
        System.out.println("======================================================================");
    }
}

下面是输出:

Print all employees...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
Employee [empNo=102, name=Racheal, gender=FEMALE, depttName=ENG, salary=90000, mgrEmpNo=0, projectName=Factory Pattern]
Employee [empNo=103, name=Kim, gender=MALE, depttName=HR, salary=150000, mgrEmpNo=0, projectName=Editorial]
Employee [empNo=104, name=Micheal, gender=FEMALE, depttName=ENG, salary=80000, mgrEmpNo=0, projectName=Decorator Pattern]
Employee [empNo=105, name=Martin, gender=MALE, depttName=SUPPORT, salary=65000, mgrEmpNo=0, projectName=Web Management]
Employee [empNo=106, name=Pierce, gender=MALE, depttName=HR, salary=130000, mgrEmpNo=0, projectName=Audit
Employee [empNo=107, name=Anjali, gender=FEMALE, depttName=ENG, salary=60000, mgrEmpNo=0, projectName=State Pattern]
Employee [empNo=108, name=Angelina, gender=FEMALE, depttName=ENG, salary=70000, mgrEmpNo=0, projectName=Flyweight Pattern]
Employee [empNo=109, name=Hemant, gender=MALE, depttName=HR, salary=170000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=110, name=Mike, gender=MALE, depttName=IT, salary=150000, mgrEmpNo=0, projectName=Networking]
======================================================================
Print all Male employees...
=====================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
Employee [empNo=103, name=Kim, gender=MALE, depttName=HR, salary=150000, mgrEmpNo=0, projectName=Editorial]
Employee [empNo=105, name=Martin, gender=MALE, depttName=SUPPORT, salary=65000, mgrEmpNo=0, projectName=Web Management]
Employee [empNo=106, name=Pierce, gender=MALE, depttName=HR, salary=130000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=109, name=Hemant, gender=MALE, depttName=HR, salary=170000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=110, name=Mike, gender=MALE, depttName=IT, salary=150000, mgrEmpNo=0, projectName=Networking]
======================================================================
Print all Male And Min Salary 140000 employees...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
Employee [empNo=103, name=Kim, gender=MALE, depttName=HR, salary=150000, mgrEmpNo=0, projectName=Editorial]
Employee [empNo=109, name=Hemant, gender=MALE, depttName=HR, salary=170000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=110, name=Mike, gender=MALE, depttName=IT, salary=150000, mgrEmpNo=0, projectName=Networking]
======================================================================

now lets try the same with the help of Java Lambda Expressions...
Print all Male employees using lambda...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
Employee [empNo=103, name=Kim, gender=MALE, depttName=HR, salary=150000, mgrEmpNo=0, projectName=Editorial]
Employee [empNo=105, name=Martin, gender=MALE, depttName=SUPPORT, salary=65000, mgrEmpNo=0, projectName=Web Management]
Employee [empNo=106, name=Pierce, gender=MALE, depttName=HR, salary=130000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=109, name=Hemant, gender=MALE, depttName=HR, salary=170000, mgrEmpNo=0, projectName=Audit]
Employee [empNo=110, name=Mike, gender=MALE, depttName=IT, salary=150000, mgrEmpNo=0, projectName=Networking]
======================================================================
Print all Male And ENG employees using lambda...
======================================================================
Employee [empNo=101, name=Brijesh, gender=MALE, depttName=ENG, salary=140000, mgrEmpNo=0, projectName=Builder Pattern]
======================================================================

你知道吗?通过使用Java 8或更高版本,我们甚至根本不需要定义过滤器,并且可以像在使用lambda时在Main中那样使用Java谓词 来创建过滤器条件。

好吧,这一切!我希望本教程有助于理解过滤器模式。


原文链接:http://codingdict.com