Tuesday, 1 October 2013

Filter or Criteria Design Pattern – Implementation

Master Practical Java Architecture & Design Patterns!

Subscribe to Ram N Java for clean coding tutorials, GoF design patterns, and real-world system implementations!

🔔 Subscribe to Ram N Java

The Challenge of Dynamic Collection Filtering

In real-world applications, systems frequently need to filter collections of business entities—such as filtering employees, products, or users based on dynamic conditions like gender, marital status, department, or price ranges.

Writing monolithic helper methods packed with tangled if-else blocks or hardcoded query conditions creates rigid, fragile code that is difficult to maintain and expand. The Filter or Criteria Design Pattern solves this problem by encapsulating filtering rules as first-class objects.

Hands-On Java Implementation Architecture

Implementing the Criteria pattern in Java follows a modular, object-oriented blueprint:

  • Model Class: A standard POJO (e.g., Person) containing attributes such as name, gender, and marital status.
  • Criteria Interface: Declares the filtering contract: public List<Person> meetCriteria(List<Person> persons);
  • Concrete Criteria: Classes implementing the interface to enforce atomic rules, such as CriteriaMale, CriteriaFemale, and CriteriaSingle.
  • Logical Combinators: Classes like AndCriteria and OrCriteria that combine multiple criteria objects to evaluate complex conditions without modifying individual filters.

Key Architectural Benefits

Structuring your business logic using the Criteria pattern delivers immediate software design benefits:

  • Open/Closed Principle: Add new filtering criteria or new logical operators without altering existing criteria classes or the domain entity.
  • High Testability & Reusability: Every filtering rule is isolated in its own class, making unit testing straightforward and enabling reuse across different layers.
  • Composability: Easily assemble complex boolean logic at runtime by chaining criteria objects dynamically.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=3-KmA2dIHT4

Click the below Image to Enlarge
Filter or Criteria Design Pattern – Implementation - Class Diagram


























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


Criteria.java

import java.util.List;

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


MaleCriteria.java

import java.util.ArrayList;
import java.util.List;

public class MaleCriteria implements Criteria
{
// Return the List of Persons who are male
@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;
}
}


FemaleCriteria.java

import java.util.ArrayList;
import java.util.List;

public class FemaleCriteria implements Criteria
{
// Return the List of Persons who are female
@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;
}
}


MarriedCriteria.java

import java.util.ArrayList;
import java.util.List;

public class MarriedCriteria implements Criteria
{
// Return the List of Persons who are Married
@Override
public List<Person> meetCriteria( List<Person> persons )
{
List<Person> marriedPersons = new ArrayList<Person>();
for( Person person : persons )
{
if( person.getMaritalStatus().equalsIgnoreCase("Married") )
{
marriedPersons.add(person);
}
}
return marriedPersons;
}
}


NotMarriedCriteria.java

import java.util.ArrayList;
import java.util.List;

public class NotMarriedCriteria implements Criteria
{

// Return the List of Persons who are not Married
@Override
public List<Person> meetCriteria( List<Person> persons )
{
List<Person> notMarriedPersons = new ArrayList<Person>();
for( Person person : persons )
{
if( person.getMaritalStatus().equalsIgnoreCase("notMarried") )
{
notMarriedPersons.add(person);
}
}
return notMarriedPersons;
}
}


CriteriaOrCondition.java


import java.util.List;

public class CriteriaOrCondition implements Criteria 
{
private Criteria criteria; /* male or female or married or notMarried Criteria  */
private Criteria otherCriteria; /* male or female or married or notMarried Criteria  */

public CriteriaOrCondition( Criteria criteria, Criteria otherCriteria )
{
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}

// This will perform OR operation of two Criteria results
@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;
}
}


CriteriaAndCondition.java

import java.util.List;

public class CriteriaAndCondition implements Criteria
{

private Criteria criteria;   /* male or female or married or notMarried Criteria  */
private Criteria otherCriteria; /* male or female or married or notMarried Criteria  */

public CriteriaAndCondition( Criteria criteria, Criteria otherCriteria )
{
this.criteria = criteria;
this.otherCriteria = otherCriteria;
}

// This will perform AND operation of two Criteria results
@Override
public List<Person> meetCriteria( List<Person> persons )
{
List<Person> firstCriteriaPersons = criteria.meetCriteria(persons);
return otherCriteria.meetCriteria(firstCriteriaPersons);
}
}


CriteriaPatternDemo.java

public class CriteriaPatternDemo
{
public static void main(String[] args)
{
List<Person> persons = new ArrayList<Person>();

persons.add(new Person("Robert", "Male", "NotMarried"));
persons.add(new Person("John", "Male", "Married"));
persons.add(new Person("Mike", "Male", "NotMarried"));
persons.add(new Person("Bobby", "Male", "NotMarried"));
persons.add(new Person("Laura", "Female", "Married"));
persons.add(new Person("Diana", "Female", "NotMarried"));

printPersons(persons);

System.out.println("---------------------------------------------------------------------");

Criteria male = new MaleCriteria();

System.out.println("Males: ");
printPersons(male.meetCriteria(persons));

Criteria female = new FemaleCriteria();

System.out.println("\nFemales: ");
printPersons(female.meetCriteria(persons));

Criteria notMarried = new NotMarriedCriteria();

System.out.println("\nNotMarried: ");
printPersons(notMarried.meetCriteria(persons));

Criteria married = new MarriedCriteria();

System.out.println("\nMarried: ");
printPersons(married.meetCriteria(persons));

Criteria marriedMale = new CriteriaAndCondition(married, male);

System.out.println("\nMarried and Male: ");
printPersons(marriedMale.meetCriteria(persons));

Criteria notMarriedOrFemale = new CriteriaOrCondition(notMarried, female);

System.out.println("\nNotMarried Or Female");
printPersons(notMarriedOrFemale.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() + " ]");
}
}
}

Output

Person : [ Name : Robert, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : John, Gender : Male, Marital Status : Married ]
Person : [ Name : Mike, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Bobby, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]
Person : [ Name : Diana, Gender : Female, Marital Status : NotMarried ]
---------------------------------------------------------------------
Males: 
Person : [ Name : Robert, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : John, Gender : Male, Marital Status : Married ]
Person : [ Name : Mike, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Bobby, Gender : Male, Marital Status : NotMarried ]

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

NotMarried: 
Person : [ Name : Robert, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Mike, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Bobby, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Diana, Gender : Female, Marital Status : NotMarried ]

Married: 
Person : [ Name : John, Gender : Male, Marital Status : Married ]
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]

Married and Male: 
Person : [ Name : John, Gender : Male, Marital Status : Married ]

NotMarried Or Female
Person : [ Name : Robert, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Mike, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Bobby, Gender : Male, Marital Status : NotMarried ]
Person : [ Name : Diana, Gender : Female, Marital Status : NotMarried ]
Person : [ Name : Laura, Gender : Female, Marital Status : Married ]

1 comment:

  1. Hey Nice Blog!!! Thank you for sharing information. Wonderful blog & good post.Its really helpful for me, waiting for a more new post. Keep Blogging!!!
    Know About Active Harmonic Filters
    Power Factor Correction with Static Var Generators

    ReplyDelete

Tutorials