passo della pipeline con due uscite che verranno utilizzate da diversi passaggi successivi

1

Sto creando un pacchetto java che offre un'API basata su un modello di pipeline. Ho una serie di passaggi che possono essere collegati in qualsiasi combinazione, a condizione che i loro ingressi corrispondano all'output del passo precedente. La fonte iniziale e il sink finale sono corretti.

Purtroppo ho un passo che alimenta il suo output in due passaggi successivi. Questo è il passo n produce una coppia di valori, uno è usato dal passo n + 1 e l'altro dal passo n + m. Il passo n + m tuttavia richiede una coppia di valori, in cui il primo proviene dal punto n + m-1 e il secondo dal punto n.

In pseudocodice questo sembra:

class Pipeline {
     Stuff runPipeline(Stuff input, List<Step> steps) {
         assert the output of every step matches the input of the one after it

         for(Step current : steps) {
             input = current.execute(input);
         }

         return input;
     }

I passaggi problematici sono simili a:

class StepN implements Step {
     Pair<Stuff,Stuff> execute(Stuff input) {
         compute two somethings
         //something1 goes to step n+1, something2 goes to step n+m
         return new Pair(something1,something2)
     }
 }    
 class StepNplusM implements Step {
     Stuff execute(Pair<Stuff,Stuff> input) {
         compute something
         //something1 comes from step n+m-1, something2 comes from step n
         return the computed something
     }
 }

Attualmente sto usando una variabile statica per qualcosa2. Ovviamente questa è una soluzione molto povera. Tuttavia, non sono sicuro di come farlo correttamente. È del tutto possibile che in futuro otterremo altri passi del genere. : (

Ho pensato di suddividere StepN up, in modo da avere un passo per qualcosa 2 che può essere eseguito quando è necessario. Sfortunatamente questi due valori sono recuperati da un servizio esterno al di fuori del nostro controllo. Calcolarli è costoso per questo servizio esterno, quindi non voglio farlo due volte.

Ho anche preso in considerazione la creazione di una sorta di archivio dati da cui ogni fase può scrivere e recuperare. Tuttavia questo rompe il modello e introduce lo stato globale.

Ho anche considerato di cambiare ogni passaggio tra il passo n e il passo n + m, in modo che accettino anche coppie (tramite sovraccarico) e semplicemente inoltrino qualcosa2. Ma cambiando fondamentalmente ogni passo ogni volta che alcuni di loro hanno bisogno di un input aggiuntivo, in realtà non lo tagliano nemmeno.

L'ultima cosa che ho considerato è di consentire più percorsi attraverso la pipeline. Questo è meno negativo delle altre idee, ma introduce molta complessità aggiuntiva che non è necessaria per nient'altro.

    
posta icehawk 11.12.2015 - 14:43
fonte

1 risposta

2

Posso pensare a due soluzioni, ognuna delle quali ha i suoi svantaggi.

In primo luogo, puoi passare attorno a un grande oggetto Context che memorizza tutto lo stato richiesto (ad esempio, contiene l'attuale Stuff più something2 ). Questa è la soluzione accettata per questo relativo domanda . Questa risposta suggerisce che ogni fase dichiara i propri requisiti di input accettando un argomento che si interfaccia con ciò di cui ha bisogno. La classe Context implementa tutte le interfacce richieste per fornire l'incapsulamento. Il rovescio della medaglia (nella mia esperienza) è che può essere difficile sapere quando creare una nuova interfaccia o quando aggiungerla a una esistente, e il contesto finisce sempre per essere enorme.

In secondo luogo, puoi modellare i tuoi stadi come funzioni in cui ogni funzione dichiara nuovamente i suoi requisiti di input in base al tipo di argomento. Puoi quindi concatenare le funzioni solo se i requisiti sono soddisfatti (ad esempio il compilatore non ti consente di mettere StepNplusM prima di StepN ). Questo è l'approccio alla composizione filtro / servizio adottato da alla libreria Finagle di Twitter . Il rovescio della medaglia è che dovrai cambiare la firma dei passaggi intermedi per passare attraverso i dati di cui non tengono conto. Tuttavia, se sei disposto a sostituire il ciclo for con un codice che richiama esplicitamente ciascun passo, puoi fare qualcosa di simile alla risposta accettata su questa domanda .

    
risposta data 14.02.2016 - 01:28
fonte