Design pattern per un generatore di filtri dinamico

0

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.

    
posta Samir Aguiar 17.11.2015 - 21:23
fonte

1 risposta

1

Utilizza Linq dinamico

Dynamiclinqconsentediscriverequery"tipizzate a stringa" con istruzioni condizionali che possono essere create e risolte in fase di esecuzione anziché in fase di compilazione.

Ulteriori letture
Guida introduttiva a Linq dinamico

    
risposta data 18.11.2015 - 09:02
fonte

Leggi altre domande sui tag