2016-07-02 10 views
2

Ich entwerfe eine einfache Datenverarbeitungspipeline in Scala. Es handelt sich um PipelineStage, die transform einige StageOutput in eine andere StageOutput. A Pipeline ist ein Wrapper für eine Sequenz von PipelineStage, die generisch auf alle ihre transform Methoden zugreifen müssen.Scala - Implementieren eines polymorphen abstrakten Merkmals ohne Polymorphismus

Allerdings habe ich Probleme, da beide Lösungen, die ich mir ausgedacht habe, grundsätzlich nicht funktionieren ... der erste beruht auf einer abstrakten polymorphen Methode, die nicht-polymorph implementiert ist (nicht kompiliert) und die zweite beruht auf der Fähigkeit, eine Seq[AbstractTrait] zu verwenden, wobei die AbstractTrait polymorph ist, was wiederum für den Compiler bedeutungslos ist. Siehe unten ...

Szenario 1. Machen Sie die transform Methode polymorph.

abstract trait PipelineStage { 
     def transform[A <: StageOutput, B <: StageOutput](in: A): B 
    } 

    class PipelineStage2 extends PipelineStage { 
     def transform(in: StageOutput1): StageOutput2 
    } 

    class Pipeline { 
     def stages: Seq[PipelineStage] 
    } 

Hier die Pipeline hat keine Probleme kompilieren, aber die Stufen nicht, da die Unterschrift ihrer transform Methoden, während sie ‚Respekt‘ der abstrakten Unterschrift des Polymorphismus kompilieren, sind eigentlich nicht selbst polymorph also nicht so weit wie der Compiler betrifft.

Szenario 2. Machen Sie das Merkmal PipelineStage selbst polymorph.

abstract trait PipelineStage[A <: StageOutput, B <: StageOutput] { 
     def transform(in: A): B 
    } 

    class PipelineStage2 extends PipelineStage[StageOutput1, StageOutput2] { 
     def transform(in: StageOutput1): StageOutput2 
    } 

    class Pipeline { 
     def stages: Seq[PipelineStage] 
    } 

Dies löst das Problem für die PipelineStage s, haben sie keine Probleme kompilieren, und ihre Methoden verwandeln arbeiten an ihrer eigenen Ordnung. Sie sind jedoch nicht technisch die gleiche Eigenschaft implementieren jetzt, so Pipeline nicht kompilieren, da Seq[PipelineStage] sinnlos ist jetzt ...

Gibt es ein etabliertes Muster entweder für die Umsetzung polymorphe abstrakte Methoden ohne den Polymorphismus oder Verweisen auf eine Sequenz von Klassen, die dieselbe abstrakte polymorphe Eigenschaft implementieren? Mein Gefühl ist nein und das habe ich wahrscheinlich falsch angegangen, aber vielleicht gibt es einen syntaktischen Trick, den ich irgendwo auf der Linie vermisse. Vielen Dank.

+1

Versuchen Sie, den Körper der 'Pipeline'-Methode auszufüllen, vorausgesetzt, Sie haben es irgendwie kompiliert und haben Zugriff auf' def stages: Seq [PipelineStage] '. Zeigen Sie an, wie genau Sie diese Funktion verwenden möchten. – Dima

Antwort

4

Die erste nicht tun, was Sie überhaupt wollen: StageOutput1 und 2 in def transform[StageOutput1, StageOutput2](in: StageOutput1): StageOutput2 sind nur Parameternamen, bedeutet es genau das gleiche wie def transform[A, B](in: A): B.

Mein Vorschlag wäre, den zweiten zu benutzen, aber statt class Pipeline können Sie

def compose[C <: StageOutput](other: PipelineStage[B, C]): PipelineStage[A, C] = new PipelineStage[A, C] { 
    def transform(in: A) = other.transform(PipelineStage.this.transform(in)) 
} 

hinzufügen und die Pipeline aufbauen Sie wollen, vorausgesetzt, dass die Typen tatsächlich entsprechen.

(Auch Ihre PipelineStage ist im Grunde ein Function1 mit einer Einschränkung, wenn Sie nicht andere Methoden planen hinzuzufügen, oder um absichtlich die Arten von Stufen zu begrenzen, die geschrieben werden können, mögen Sie vielleicht nur Funktionen nutzen und nehmen Vorteil der Standard-Bibliothek!)

+0

Sie haben absolut Recht, bearbeitet, um den Polymorphismus in der 'transform'-Methode des ersten Szenarios 'PipelineStage1' zu entfernen. War ein Tippfehler und nicht das, was ich versucht hatte zu kompilieren. Außerdem habe ich einige andere Methoden und Attribut auf einer PipelineStage, also muss ich ein Merkmal verwenden. Allerdings habe ich nicht wirklich daran gedacht, dass es zwischen einer 'PipelineStage' und einer' Pipeline' nichts grundsätzlich Unterschiedliches gibt. Ich kann alle Methoden, die ich wollte, auf "Pipeline" auf "PipelineStage" setzen und Ihre Kompositionsfunktion verwenden. Vielen Dank! –

+0

Eigentlich würde ich vorschlagen, es "Pipeline" anstelle von "PipelineStage" zu nennen. –