Filter Pattern

Filter Pattern or Criteria Pattern is a design pattern that allows developers to filter a set of objects using different criteria and connect them in a decoupled way through logical operations. This type of design pattern belongs to structural patterns, as it combines multiple criteria to obtain a single standard.


summary

intent

Used to encapsulate the filtering process of objects, allowing objects to be dynamically filtered using different filtering criteria.

Main problems solved

When a set of objects needs to be filtered based on multiple different conditions or criteria, the Filter Pattern provides a flexible way to define these conditions, avoiding hardcoding filtering logic in client code.

Use Case

  • When an object collection needs to be filtered according to different criteria.
  • When the filtering logic may change, or when multiple filtering conditions need to be dynamically combined.

Implementation Approach

  • Define filter interface: Create a filter interface and define a filtering method.
  • Implement concrete filters: Implement the filter interface for each filtering criterion, encapsulating the specific filtering logic.
  • Composite filter: Allow filters to be combined to form complex filtering logic.

Key code

  • Filter Interface: Define the filtering method, such asmatches()。
  • Concrete filter class: Implement the filter interface and encapsulate the specific filtering logic.
  • Composite filter: Implement combination logic for filters, such as logical AND, logical OR, etc.

Application example

  1. Book management system: Filter books according to different criteria such as author, publication year, and category.
  2. Online shopping platform: Filter products based on conditions such as price, brand, and user rating.

Advantages

  1. Encapsulation: Filtering logic is encapsulated in independent filter objects.
  2. Flexibility: Filtering conditions can be dynamically added, modified, or combined.
  3. Extensibility: New filtering criteria can be easily added without modifying existing code.

Disadvantages

  • Complexity: As filtering conditions increase, the system may become complex.
  • Performance issues: If the filter combination is too complex, performance may be affected.

Usage suggestions

  • When filtering logic may change or objects need to be dynamically filtered according to different criteria, consider using the Filter Pattern.
  • During design, ensure that the filter interface and its implementations remain consistent to facilitate combination and extension.

Notes

  • Ensure that the combination logic of filters is correct to avoid introducing logical errors.
  • During implementation, consider the performance impact, especially when processing large amounts of data.

summary

The Filter Pattern includes the following main roles:

  • Filter Interface (Filter/Criteria): Define an interface for filtering objects. This interface usually contains a method for filtering objects based on specific conditions.

  • Concrete Filter Classes (Concrete Filter/Concrete Criteria): Implement the filter interface to specifically define the conditions and logic for filtering objects.

  • Object Collection (Items/Objects to be filtered): The collection of objects to be filtered. These objects are usually instances with common attributes, such as a group of people, a group of products, etc.

  • Client: Use concrete filter classes to filter object collections. The client combines the object collection with filters to obtain objects that meet the criteria.

Implementation

We will create aPersonObject,CriteriaThe interface and entity classes that implement the interface, to filterPersonlist of objects.CriteriaPatternDemoClass usageCriteriaobjects, filter based on various criteria and their combinationsPersonlist of objects.

过滤器模式的 UML 图

Step 1

Create a class on which the criteria are applied.

Person.java

public class Person { private String name; private String gender; private String maritalStatus; public Person(String name,String gender,String maritalStatus){ this.name = name; this.gender = gender; this.maritalStatus = maritalStatus; } public String getName() { return name; } public String getGender() { return gender; } public String getMaritalStatus() { return maritalStatus; } }

Step 2

Create an interface for Criteria.

Criteria.java

import java.util.List; public interface Criteria { public List<Person> meetCriteria(List<Person> persons); }

Step 3

Create an ImplementationCriteriaEntity class of the interface.

CriteriaMale.java

import java.util.ArrayList; import java.util.List; public class CriteriaMale implements Criteria { @Override public List<Person> meetCriteria(List<Person> persons) { List<Person> malePersons = new ArrayList<Person>(); for (Person person : persons) { if(person.getGender().equalsIgnoreCase("MALE")){ malePersons.add(person); } } return malePersons; } }

CriteriaFemale.java

import java.util.ArrayList; import java.util.List; public class CriteriaFemale implements Criteria { @Override public List<Person> meetCriteria(List<Person> persons) { List<Person> femalePersons = new ArrayList<Person>(); for (Person person : persons) { if(person.getGender().equalsIgnoreCase("FEMALE")){ femalePersons.add(person); } } return femalePersons; } }

CriteriaSingle.java

import java.util.ArrayList; import java.util.List; public class CriteriaSingle implements Criteria { @Override public List<Person> meetCriteria(List<Person> persons) { List<Person> singlePersons = new ArrayList<Person>(); for (Person person : persons) { if(person.getMaritalStatus().equalsIgnoreCase("SINGLE")){ singlePersons.add(person); } } return singlePersons; } }

AndCriteria.java

import java.util.List; public class AndCriteria implements Criteria { private Criteria criteria; private Criteria otherCriteria; public AndCriteria(Criteria criteria, Criteria otherCriteria) { this.criteria = criteria; this.otherCriteria = otherCriteria; } @Override public List<Person> meetCriteria(List<Person> persons) { List<Person> firstCriteriaPersons = criteria.meetCriteria(persons); return otherCriteria.meetCriteria(firstCriteriaPersons); } }

OrCriteria.java

import java.util.List; public class OrCriteria implements Criteria { private Criteria criteria; private Criteria otherCriteria; public OrCriteria(Criteria criteria, Criteria otherCriteria) { this.criteria = criteria; this.otherCriteria = otherCriteria; } @Override public List<Person> meetCriteria(List<Person> persons) { List<Person> firstCriteriaItems = criteria.meetCriteria(persons); List<Person> otherCriteriaItems = otherCriteria.meetCriteria(persons); for (Person person : otherCriteriaItems) { if(!firstCriteriaItems.contains(person)){ firstCriteriaItems.add(person); } } return firstCriteriaItems; } }

Step 4

Use different Criteria and their combinations to filterPersonlist of objects.

CriteriaPatternDemo.java

import java.util.ArrayList; import java.util.List; public class CriteriaPatternDemo { public static void main(String[] args) { List<Person> persons = new ArrayList<Person>(); persons.add(new Person("Robert","Male", "Single")); persons.add(new Person("John","Male", "Married")); persons.add(new Person("Laura","Female", "Married")); persons.add(new Person("Diana","Female", "Single")); persons.add(new Person("Mike","Male", "Single")); persons.add(new Person("Bobby","Male", "Single")); Criteria male = new CriteriaMale(); Criteria female = new CriteriaFemale(); Criteria single = new CriteriaSingle(); Criteria singleMale = new AndCriteria(single, male); Criteria singleOrFemale = new OrCriteria(single, female); System.out.println("Males: "); printPersons(male.meetCriteria(persons)); System.out.println("\nFemales: "); printPersons(female.meetCriteria(persons)); System.out.println("\nSingle Males: "); printPersons(singleMale.meetCriteria(persons)); System.out.println("\nSingle Or Females: "); printPersons(singleOrFemale.meetCriteria(persons)); } public static void printPersons(List<Person> persons){ for (Person person : persons) { System.out.println("Person : [ Name : " + person.getName() +", Gender : " + person.getGender() +", Marital Status : " + person.getMaritalStatus() +" ]"); } } }

Step 5

Run the program, output the result:

Males: 
Person : [ Name : Robert, Gender : Male, Marital Status : Single ]
Person : [ Name : John, Gender : Male, Marital Status : Married ]
Person : [ Name : Mike, Gender : Male, Marital Status : Single ]
Person : [ Name : Bobby, Gender : Male, Marital Status : Single ]

Females: 
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]
Person : [ Name : Diana, Gender : Female, Marital Status : Single ]

Single Males: 
Person : [ Name : Robert, Gender : Male, Marital Status : Single ]
Person : [ Name : Mike, Gender : Male, Marital Status : Single ]
Person : [ Name : Bobby, Gender : Male, Marital Status : Single ]

Single Or Females: 
Person : [ Name : Robert, Gender : Male, Marital Status : Single ]
Person : [ Name : Diana, Gender : Female, Marital Status : Single ]
Person : [ Name : Mike, Gender : Male, Marital Status : Single ]
Person : [ Name : Bobby, Gender : Male, Marital Status : Single ]
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]
other extensions