Dì che ho una classe base astratta Shape
e le sue classi derivate Triangle
, Square
, ecc.
Attualmente ho la seguente struttura (semplificata) per recuperare un elenco di Shape
s e filtrarli (principalmente usando Fluent):
public abstract class BaseSearch<T> where T : Shape
{
protected readonly IRepository<T> repository;
public IQueryable<T> Search(Filter filter)
{
var shapes = repository.GetAll();
// applies the common filtering to shapes
return CustomSearch(filter, shapes);
}
public abstract IQueryable<T> CustomSearch(Filter filter, IQueryable<T> shapes);
}
public class TriangleSearch : BaseSearch<Triangle>
{
public IQueryable<Triangle> CustomSearch(Filter filter, IQueryable<Triangle> shapes)
{
var filteredTriangles = shapes;
// applies filters specific to Triangles
return filteredTriangles;
}
}
Lo stesso vale per il resto della classe derivata. Devono solo implementare il metodo CustomSearch
.
Il problema è che ora luoghi diversi richiedono filtri diversi, con condizioni, proprietà e così via. Aumentare la classe Filter
per gestire quei requisiti aggiuntivi potrebbe renderlo troppo complesso.
Per risolvere questo problema, ho pensato di avere molte classi di filtri, ognuno applicherebbe il suo semplice algoritmo di filtro a un elenco di Square
s. Quindi, usando la composizione, potrei annidarli tutti e disporre dell'intero filtro di cui ho bisogno.
Il problema con questo approccio è che alcune proprietà si trovano in luoghi diversi su ciascuna entità. Ad esempio, per filtrare in base all'altezza, ho bisogno di confrontare la proprietà MiddleHeight
da Triangle
e la proprietà Height
da Square
. Inoltre, nessuna di queste proprietà è presente nella classe Square
.
Ho anche pensato di utilizzare l'approccio Predicate Builder , ma vorrei cadere nello stesso problema.
Che cosa potrebbe essere utilizzato per implementare un filtro più generale o dinamico che potrebbe essere utilizzato per filtrare le istanze di classi derivate da Shape
e restituire ancora un IQueryable
di forme?
Modifica: spiega ulteriormente la classe del filtro e il suo utilizzo.
public class Filter {
public string Color { get; set; }
}
public class AnotherFilter {
public Filter MainFilter { get; set; }
public long? Height { get; set; }
}
La ricerca principale utilizza la classe Filter
. Controlla se la proprietà Color
è impostata e in tal caso applica una condizione alla raccolta di forme. Questa condizione non è sempre un semplice "dove il colore della forma corrisponde al set di colori nel filtro"; a volte la proprietà richiede un controllo più complesso (ad esempio "dove il colore della forma corrisponde a quello del filtro e la forma ha l'opacità impostata su 0%").
La classe AnotherFilter
rappresenta un filtro diverso. Attualmente ha una proprietà Filter
che viene utilizzata per chiamare il Search
principale e recuperare alcuni risultati. Quindi, utilizzando le proprietà di AnotherFilter
, la raccolta viene ulteriormente filtrata. C'è anche un problema qui menzionato prima: la proprietà Height
deve essere usata per filtrare i dati per altezza. Ma Height
non è una proprietà di Shape
, solo di, per esempio, Triangle
e Square
(a Circle
, che eredita anche da Shape
, non ha altezza).
La ricerca recupera i dati da un database remoto e utilizza NHibernate.