Patrón de filtro

El patrón de filtro (Filter Pattern) o patrón de criterio (Criteria Pattern) es un patrón de diseño que permite a los desarrolladores utilizar diferentes criterios para filtrar un grupo de objetos, conectándolos mediante operaciones lógicas de forma desacoplada. Este tipo de patrón de diseño pertenece a los patrones estructurales, y combina múltiples criterios para obtener un único criterio.


Resumen

Intención

Se utiliza para encapsular el proceso de filtrado de objetos, permitiendo filtrar objetos dinámicamente con diferentes criterios de filtrado.

Problema principal que resuelve

Cuando es necesario filtrar un grupo de objetos según múltiples condiciones o criterios diferentes, el patrón de filtro proporciona una forma flexible de definir estas condiciones, evitando codificar de manera fija la lógica de filtrado en el código del cliente.

Escenarios de uso

  • Cuando una colección de objetos necesita filtrarse según diferentes criterios.
  • Cuando la lógica de filtrado puede cambiar, o es necesario combinar dinámicamente múltiples condiciones de filtrado.

Forma de implementación

  • Definir la interfaz de filtrado: crear una interfaz de filtrado y definir un método de filtrado.
  • Implementar filtros concretos: implementar la interfaz de filtrado para cada criterio de filtrado, encapsulando la lógica de filtrado específica.
  • Combinar filtros: permitir la combinación entre filtros para formar una lógica de filtrado compleja.

Código clave

  • Interfaz de filtrado: definir el método de filtrado, comomatches()。
  • Clases de filtro concretas: implementan la interfaz de filtrado y encapsulan la lógica de filtrado específica.
  • Filtro combinado: implementa la lógica de combinación de filtros, como AND (lógica AND), OR (lógica OR), etc.

Ejemplos de aplicación

  1. Sistema de gestión de bibliotecas: filtrar libros según diferentes criterios como autor, año de publicación, categoría, etc.
  2. Plataforma de compras en línea: filtrar productos según condiciones como precio, marca, valoración de usuarios, etc.

Ventajas

  1. Encapsulamiento: la lógica de filtrado se encapsula en objetos de filtro independientes.
  2. Flexibilidad: se pueden agregar, modificar o combinar condiciones de filtrado dinámicamente.
  3. Extensibilidad: es fácil agregar nuevos criterios de filtrado sin modificar el código existente.

Desventajas

  • Complejidad: el sistema puede volverse complejo a medida que aumentan las condiciones de filtrado.
  • Problemas de rendimiento: si la combinación de filtros es demasiado compleja, puede afectar el rendimiento.

Recomendaciones de uso

  • Cuando la lógica de filtrado pueda cambiar o se necesite filtrar objetos dinámicamente según diferentes criterios, considere usar el patrón de filtro.
  • Al diseñar, asegúrese de que la interfaz y la implementación del filtro sean coherentes para facilitar la combinación y la extensión.

Consideraciones

  • Asegúrese de que la lógica de combinación de filtros sea correcta para evitar introducir errores lógicos.
  • Al implementar, tenga en cuenta el impacto en el rendimiento, especialmente al manejar grandes volúmenes de datos.

Resumen

El patrón de filtro incluye los siguientes roles principales:

  • Interfaz de filtro (Filter/Criteria): define una interfaz para filtrar objetos. Esta interfaz suele contener un método para filtrar objetos según condiciones específicas.

  • Clase de filtro concreta (Concrete Filter/Concrete Criteria): implementa la interfaz de filtro y define concretamente las condiciones y la lógica para filtrar objetos.

  • Colección de objetos (Items/Objects to be filtered): la colección de objetos que se va a filtrar. Estos objetos suelen ser instancias con atributos comunes, por ejemplo, un grupo de personas, un grupo de productos, etc.

  • Cliente (Client): usa las clases de filtro concretas para filtrar la colección de objetos. El cliente combina la colección de objetos y los filtros para obtener los objetos que cumplen las condiciones.

Implementación

Crearemos unPersonobjeto,Criteriainterfaz y clases de entidad que implementan dicha interfaz para filtrarPersonla lista de objetos.CriteriaPatternDemoLa clase utilizaCriteriaobjetos, basándose en varios criterios y sus combinaciones para filtrarPersonla lista de objetos.

过滤器模式的 UML 图

Paso 1

Crear una clase sobre la que se aplicarán los criterios.

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

Paso 2

Crear una interfaz para el criterio (Criteria).

Criteria.java

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

Paso 3

CrearCriterialas clases de entidad que implementan la interfaz.

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

Paso 4

Usar diferentes criterios (Criteria) y sus combinaciones para filtrarPersonla lista de objetos.

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

Paso 5

Ejecutar el programa y mostrar el resultado:

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 ]
Otras extensiones