Pipeline di trasformazione dei dati

1

Ho creato una sorta di pipeline di dati per trasformare i dati delle coordinate in informazioni più utili.

Ecco la shell della pipeline:

public class PositionPipeline
{
    protected List<IPipelineComponent> components;

    public PositionPipeline()
    {
        components = new List<IPipelineComponent>();
    }

    public PositionPipelineEntity Process(Position position)
    {
        foreach (var component in components)
        {
            position = component.Execute(position);
        }

        return position;
    }

    public PositionPipeline RegisterComponent(IPipelineComponent component)
    {
        components.Add(component);
        return this;
    }
}

Ogni IPipelineComponent accetta e restituisce lo stesso tipo - a PositionPipelineEntity . Codice:

public interface IPipelineComponent
{
    PositionPipelineEntity Execute(PositionPipelineEntity position);
}

Il PositionPipelineEntity deve avere molte proprietà, molte che sono non utilizzate in alcuni componenti e richieste in altri . Alcune proprietà saranno ridondanti anche alla fine della pipeline.

Ad esempio, questi componenti potrebbero essere eseguiti:

  1. TransformCoordinatesComponent : analizza i dati di coordinate grezzi in un tipo di coordinate.
  2. DetermineCountryComponent : determina e memorizza il codice paese.
  3. DetermineOnRoadComponent : determina e memorizza se le coordinate sono su una strada.

Codice:

pipeline
    .RegisterComponent(new TransformCoordinatesComponent())
    .RegisterComponent(new DetermineCountryComponent())
    .RegisterComponent(new DetermineOnRoadComponent());

pipeline.Process(positionPipelineEntity);

Il tipo PositionPipelineEntity :

public class PositionPipelineEntity
{
    // Only relevant to the TransformCoordinatesComponent 
    public decimal RawCoordinateLatitude { get; set; }

    // Only relevant to the TransformCoordinatesComponent 
    public decimal RawCoordinateLongitude { get; set; }

    // Required by all components after TransformCoordinatesComponent 
    public Coordinate CoordinateLatitude { get; set; }

    // Required by all components after TransformCoordinatesComponent 
    public Coordinate CoordinateLongitude { get; set; }

    // Set in DetermineCountryComponent, not required anywhere.  
    // Requires CoordinateLatitude and CoordinateLongitude (TransformCoordinatesComponent)
    public string CountryCode { get; set; }

    // Set in DetermineOnRoadComponent, not required anywhere.  
    // Requires CoordinateLatitude and CoordinateLongitude (TransformCoordinatesComponent)
    public bool OnRoad { get; set; }
}

Problemi:

  • Sono molto preoccupato per la dipendenza che un componente ha sulle proprietà. Il modo per risolvere questo sarebbe creare tipi specifici per ciascun componente. Il problema quindi è che non posso incatenarli insieme in questo modo.

  • L'altro problema riguarda l'ordine dei componenti nella pipeline. C'è qualche dipendenza. La struttura attuale non fornisce alcun controllo statico o di runtime per una cosa del genere.

Qualsiasi feedback sarebbe apprezzato.

    
posta davenewza 23.10.2013 - 10:10
fonte

1 risposta

1

Mi sembra che il tuo problema qui sia in parte dovuto al fatto che la tua pipeline è un po 'troppo astratta. È importante lavorare con le astrazioni, ma l'apertura del design che hai sta rendendo difficile la visualizzazione della soluzione.

Ad esempio, con l'ordine dei componenti, probabilmente vorrai suddividerli nella pipeline, in modo che

pipeline
.RegisterComponent(new TransformCoordinatesComponent())
.RegisterComponent(new DetermineCountryComponent())
.RegisterComponent(new DetermineOnRoadComponent());

Potrebbe diventare qualcosa di simile

pipeline.TransformationCoordinates.Register(new TransformCoordinatesComponent());
pipeline.Determinations.Register(new DetermineCountryComponent());
pipeline.Determinations.Register(new DetermineOnRoadComponent());

Quindi la tua granularità diventa quella del numero di diversi tipi di componenti ordinati che devi avere, quindi la pipeline può avere zero o molti componenti TransformationCoordinate , componenti Determination e così via ed eseguirà tutti quelli disponibili in ordine. Ovviamente, questo potrebbe essere nascosto all'interno di pipeline.RegisterComponent suddividendolo per interfaccia, ma questo è un modo più semplice per illustrare cosa intendo.

Man mano che diventi meno astratto perdi flessibilità, in questo caso avresti bisogno di avere una nuova collezione se hai aggiunto un nuovo tipo ordinato, quindi se vuoi avere un InvertComponent che è stato eseguito tra TransformationCoordinate e il Determination componenti dovresti cambiare la tua pipeline di conseguenza. Questa probabilmente non è una cosa terribile, purché la tua architettura sia generalmente solida, tuttavia è probabile che tu debba fare il salto dal teorico al pragmatico ad un certo punto comunque.

Una volta che conosci i diversi tipi di componenti, puoi garantire di disporre delle proprietà corrette per ogni fase del processo: potresti garantire che le proprietà siano impostate su ogni passaggio di un tipo che le ha sempre disponibili o che potresti restituire un nuovo oggetto da ogni fase con le proprietà necessarie per il prossimo.

In ogni caso, penso che troverai che il tuo lavoro è più semplice se inizi a pensare in termini più concreti sui processi esatti che devi seguire.

    
risposta data 23.10.2013 - 18:46
fonte