2009-10-25 13 views
14

Imagine el tipo de aplicación típica donde tiene una lista de elementos con diferentes propiedades. P.ej. una vista de árbol con 100 elementos, cada uno con un nombre , un calificación, un rango-dentro-de-los-más-calientes-en-el-planeta etc. Probablemente también hay relaciones de muchos a muchos entre artículos y artículo catálogos, o entre elementos y item-creadores, etc, etc¿Patrón de diseño para filtrar una colección de elementos?

Ahora esta aplicación, naturalmente, necesita un sistema de filtrado. P.ej. donde puedo construir filtros complejos con múltiples condiciones de todo tipo, entre datos en diferentes relaciones.

La tarea de diseño de escribir esta función de filtrado debe ser algo que MUCHOS desarrolladores han hecho y seguramente debe haber algún tipo de patrón de diseño que sea el más adecuado para la tarea.

¿Alguien?

Editar: Cambié a la wiki de la comunidad ya que sospecho que no hay ningún patrón de factor de industria utilizado para esto. Pregunta demasiado formulada en general, supongo.

+0

En cualquier momento que esté buscando cambiar los algoritmos, y la forma de ordenar sería un algoritmo (definido vagamente), el patrón de estrategia es la solución lógica, pero la implementación está abierta a debate.

+0

[Patrón de diseño de filtro con ejemplo] (http://www.singhajit.com/filter-design-pattern/) –

Respuesta

6

Es un poco difícil señalar lo que realmente quiere, así que asumiré mis propias suposiciones.

  1. La colección subyacente debe ser cambiado después del filtrado
  2. El resultado no es persistente

Un enfoque clásico es el uso de vistas. Esto es básicamente programación diferida, donde crea un objeto que puede acceder a la colección original y conoce el filtro para aplicar, pero no realizará ningún cálculo mientras no se requiera nada.

En las colecciones, las vistas a menudo se implementan con iteradores, y para el filtrado, por supuesto, un Patrón de estrategia como ya se señaló.

Por ejemplo:

Collection myCollection; 
Predicate myFilter; 

// Nothing is computed here 
View<Predicate> myView(myCollection, myFilter); 

// We iterate until we find the first item in the collection that satisfies 
// the Predicate, and no more, to initialize `begin` 
View<Predicate>::Iterator begin = myView.begin(), end = myView.end(); 

La ventaja neta es que si (por ejemplo), sólo necesita los 10 primeros artículos, entonces usted sólo se aplica el predicado tanto como sea necesario para encontrar a los 10 primero, y no más.

Además, no hay copia de los elementos implicados, y se garantiza que su vista se actualizará aunque modifique myCollection, aunque esto puede afectar la validez de los iteradores (como es habitual).

El problema es que (a menos que implemente el almacenamiento en caché), el resultado se calcula cada vez.

Si desea obtener un resultado más persistente, será mejor que cree una nueva colección que contenga solo los elementos filtrados (o referencias a ellos). No hay un patrón general aquí porque depende de cómo quiera usar la lista 'filtrada'.

En cuanto al Patrón de Estrategia sugerido, generalmente puede construir su filtro por bloque usando el Patrón Compuesto y luego pasar el objeto así construido como la estrategia.

El patrón compuesto es especialmente adecuado para representar el resultado de una expresión analizada, por ejemplo, es posible que desee echar un vistazo a los árboles de expresiones para tener una idea.

+1

Me gusta mucho la idea de combinar el patrón Compuesto y Estrategia, ¡gracias! – sharkin

0

Si estas relaciones se pueden expresar como RDF y OWL, puede usar una herramienta con un punto final SPARQL (como Jena) o un razonador como Pellet. Pero sin más detalles, no está claro que este sea el mejor enfoque.

1

No conozco un patrón de diseño para él, pero puede ver algunos de los enfoques que se han hecho para la clasificación, y sería útil si explicara algunos de ellos y por qué no le gustaba ellos como un ejemplo.

Por ejemplo, LINQ tiene una buena manera de ordenar, usando los árboles Expression.

También puede ver la ordenación realizada en idiomas funcionales, donde puede pasar la función para hacer la ordenación, en lugar de codificar en un tipo particular.

Si estaba trabajando en algo así como javascript, la función de ordenación podría crearse sobre la marcha.

+0

El patrón de estrategia puede ser bueno para mirar, como punto de partida. –

1

Su búsqueda de una base de datos relacional, desde la cual puede usar SQL. Puede ponerse de pie uno completo y conectarse a él desde su aplicación, o puede hacer algo entre una base de datos completa y objetos rectos. En Java, por ejemplo, podría usar una base de datos en memoria como HSQLDB/JavaDB y usar las características de eso. También puede usar JoSQL que le permitirá operar en SQL directamente en sus objetos sin la base de datos en absoluto.

Alternativamente, si quisiera programar la cosa usted mismo, comenzaría manteniendo 2 copias de sus datos. Uno es su conjunto completo de datos, el otro es su vista de los datos después del filtrado. Luego, crearía un índice en sus datos para cada columna, clasificando los datos y manteniendo su posición en la lista ordenada. La misma configuración funciona para una coincidencia de filtro. Si algo coincide con un filtro para una columna, déle un 1, o 0 si no. Luego, cuando alguien cambie el orden de clasificación, copie los datos de la lista completa en la lista de vistas, o cuando cambie la información del filtro, solo tomará los datos que coincidan.

+0

Me gusta la idea de usar expresiones SQL como base para la mecánica de filtros. De lo contrario, creo que este enfoque me prohibiría abstraer la base de datos como una capa de almacenamiento anónima e intercambiable. Corrígeme si estoy equivocado. – sharkin

1

Me gusta el filtro con el predicado de Google Collections y implementaría algo muy similar si no pudiera usarlo.Es posible que desee comprobar this answer a una pregunta similar para un ejemplo de implementación. La implementación está en Java pero, bueno, verá el patrón.

+0

Muy interesante. Eso parece una forma de patrón de estrategia, también señalado por James Black. – sharkin