Filter Pattern
# Filter Pattern
## Filter Pattern
The Filter Pattern, also known as the Criteria Pattern, is a design pattern that allows developers to filter a set of objects using different criteria, connecting them in a decoupled manner through logical operations. This type of design pattern belongs to the structural pattern category, combining multiple criteria to obtain a single result.
* * *
## Overview
### Intent
To encapsulate the process of filtering objects, allowing for dynamic filtering of objects using different filtering criteria.
### Main Problem 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 the hardcoding of filtering logic in client code.
### Use Cases
* When an object collection needs to be filtered based on different criteria.
* When the filtering logic may change, or when multiple filtering conditions need to be dynamically combined.
### Implementation Approach
* **Define a Filtering Interface**: Create a filtering interface that defines a filtering method.
* **Implement Concrete Filters**: Implement the filtering interface for each filtering criterion, encapsulating the specific filtering logic.
* **Combine Filters**: Allow filters to be combined to form complex filtering logic.
### Key Code
* **Filtering Interface**: Defines the filtering method, such as `matches()`.
* **Concrete Filter Class**: Implements the filtering interface, encapsulating specific filtering logic.
* **Combined Filter**: Implements the logic for combining filters, such as logical AND, logical OR, etc.
### Application Examples
1. **Library Management System**: Filtering books based on different criteria such as author, publication year, and category.
2. **Online Shopping Platform**: Filtering products based on conditions like price, brand, and user ratings.
### Advantages
1. **Encapsulation**: Filtering logic is encapsulated in independent filter objects.
2. **Flexibility**: Filtering conditions can be dynamically added, modified, or combined.
3. **Extensibility**: Easy to add new filtering criteria without modifying existing code.
### Disadvantages
* **Complexity**: As the number of filtering conditions increases, the system may become complex.
* **Performance Issues**: If the combination of filters becomes too complex, it may impact performance.
### Usage Recommendations
* Consider using the Filter Pattern when the filtering logic may change or when objects need to be dynamically filtered based on different criteria.
* During design, ensure that the interface and implementation of the filters remain consistent to facilitate combination and extension.
### Notes
* Ensure the combination logic of the filters is correct to avoid introducing logical errors.
* During implementation, consider performance impacts, especially when processing large amounts of data.
### Summary
The Filter Pattern includes the following main roles:
* **Filter Interface (Filter/Criteria)**: Defines an interface for filtering objects. This interface typically contains a method for filtering objects based on specific conditions.
* **Concrete Filter Class (Concrete Filter/Concrete Criteria)**: Implements the filter interface, specifically defining the conditions and logic for filtering objects.
* **Object Collection (Items/Objects to be filtered)**: The collection of objects to be filtered. These objects are typically instances with common attributes, such as a group of people, a group of products, etc.
* **Client**: Uses concrete filter classes to filter the object collection. The client combines the object collection with the filters to obtain objects that meet the criteria.
We will create a _Person_ object, a _Criteria_ interface, and entity classes that implement this interface to filter a list of _Person_ objects. The _CriteriaPatternDemo_ class uses _Criteria_ objects to filter the list of _Person_ objects based on various criteria and their combinations.

### Step 1
Create a class on which the criteria will be applied.
## Person.java
```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 the criteria.
## Criteria.java
```java
import java.util.List;
public interface Criteria {
public List meetCriteria(List persons);
}
### Step 3
Create entity classes that implement the _Criteria_ interface.
## CriteriaMale.java
```java
import java.util.ArrayList;
import java.util.List;
public class CriteriaMale implements Criteria {
@Override
public List meetCriteria(List persons) {
List malePersons = new ArrayList();
for (Person person : persons) {
if (person.getGender().equalsIgnoreCase("MALE")) {
malePersons.add(person);
}
}
return malePersons;
}
}
## CriteriaFemale.java
```java
import java.util.ArrayList;
import java.util.List;
public class CriteriaFemale implements Criteria {
@Override
public List meetCriteria(List persons) {
List femalePersons = new ArrayList();
for (Person person : persons) {
if (person.getGender().equalsIgnoreCase("FEMALE")) {
femalePersons.add(person);
}
}
return femalePersons;
}
}
## CriteriaSingle.java
```java
import java.util.ArrayList;
import java.util.List;
public class CriteriaSingle implements Criteria {
@Override
public List meetCriteria(List persons) {
List singlePersons = new ArrayList();
for (Person person : persons) {
if (person.getMaritalStatus().equalsIgnoreCase("SINGLE")) {
singlePersons.add(person);
}
}
return singlePersons;
}
}
## AndCriteria.java
```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 meetCriteria(List persons) {
List firstCriteriaPersons = criteria.meetCriteria(persons);
return otherCriteria.meetCriteria(firstCriteriaPersons);
}
}
## OrCriteria.java
```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 meetCriteria(List persons) {
List firstCriteriaItems = criteria.meetCriteria(persons);
List 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 filter the list of _Person_ objects.
## CriteriaPatternDemo.java
```java
import java.util.ArrayList;
import java.util.List;
public class CriteriaPatternDemo {
public static void main(String[] args) {
List persons = new ArrayList();
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 persons) {
for (Person person : persons) {
System.out.println("Person : [ Name : " + person.getName()
+ ", Gender : " + person.getGender()
+ ", Marital Status : " + person.getMaritalStatus() + " ]");
}
}
}
### Step 5
Execute the program, and the output will be:
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 ]
YouTip