Filter Pattern

Filter Pattern is a structural pattern that enables developers to filter a set of objects using different criteria and chaining them in a decoupled way through logical operations. This pattern combines multiple criteria to obtain single criteria.

The following example comprises the following objects : Person object, Criteria interface and concrete classes implementing Criteria interface to filter list of Person objects. CriteriaPatternDemo uses Criteria objects to filter list of Person objects based on various criteria and their combinations.

Filter Pattern UML Diagram

Step 1 : Create a class on which criteria is to be applied

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

public interface Criteria {
List<Person> meetCriteria(List<Person> persons);
}

Step 3 : Create concrete classes implementing the Criteria interface

public class CriteriaMale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
return persons.stream()
.filter(person -> person.getGender().equalsIgnoreCase("MALE"))
.collect(Collectors.toList());
}
}

public class CriteriaFemale implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
return persons.stream()
.filter(person -> person.getGender().equalsIgnoreCase("FEMALE"))
.collect(Collectors.toList());
}
}

public class CriteriaSingle implements Criteria {
@Override
public List<Person> meetCriteria(List<Person> persons) {
return persons.stream()
.filter(person -> person.getMaritalStatus().equalsIgnoreCase("SINGLE"))
.collect(Collectors.toList());
}
}

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) {
UnaryOperator<List<Person>> firstCriteriaPersons
= initialPersons -> criteria.meetCriteria(persons);
UnaryOperator<List<Person>> otherCriteriaPersons
= firstCriteriaAppliedPersons -> otherCriteria.meetCriteria(firstCriteriaAppliedPersons);
return firstCriteriaPersons.andThen(otherCriteriaPersons).apply(persons);
}
}


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);

List<Person> addToFirstCriteriaItems = otherCriteriaItems.stream()
.filter(person -> !firstCriteriaItems.contains(person))
.collect(Collectors.toList());

firstCriteriaItems.addAll(addToFirstCriteriaItems);

return firstCriteriaItems;
}
}

Step 4 : Use different Criteria and their combination to filter out persons

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() + " ]");
}
}
}

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 ]

Leave a Reply

Your email address will not be published. Required fields are marked *