2016-04-10 2 views
0

Ich habe eine Webanwendung auf Play-Framework gebaut.Scala-Klassennamen in Konfigurationskarte

Einer meiner Endpunkte bietet eine Antwort, die aus Ausgaben verschiedener Klassen besteht. Der Verbraucher kann wählen, welche Teile der Ausgabe er in der Antwort haben möchte: GET /model/:modelId?fields=length,width,age. Dementsprechend habe ich LengthProvider, WidthProvider. Jetzt will ich in der Steuerung eine Konfigurationskarte haben, wie

val providers = Map(
    "length" -> LengthProvider, 
    "width" -> WidthProvider 
) 

der Lage sein Eingang zu filtern Verbraucher von dieser Karte und gelten alle Anbieter, wie

fields.collect { 
    case field if providers.contains(field) => providers(field)(db).get(modelId) 
    } 

Das Problem entsteht, wenn Ich versuche, entsprechende Klassen zu bauen. Ich habe eine abstrakte FieldProvider:

abstract class FieldProvider(db: DB) { 
    def get(modelId: Long): Future[Seq[Writes]] 
} 

und entsprechende Implementierungen (LengthProvider, WidthProvider). Um nun die Konfiguration Map kompilieren zu können, muss ich Begleitobjekte für die Klassen definieren, auf die ich verweisen möchte (z. B. brauche ich LengthProvider Objekt). Und dann, wenn ich den Wert der Map (Klassenname) verwende, kann ich die Klasseninstanz nicht so initialisieren, wie ich das normalerweise tue, ich habe nur Zugriff auf die in Companion-Objekt definierte Methode apply. Aber das Problem ist, dass dies nicht Teil der abstrakten Klasse ist, die ich definiere, so dass der Compiler die Methodensignatur apply nicht versteht (da sie nur in Companion-Objekten der Unterklassen und nicht in der abstrakten Elternklasse definiert ist):

fields.collect { 
    case field if providers.contains(field) => providers(field)(db).get(modelId) 
                   ↑ won't compile 
    } 

Gibt es eine Möglichkeit, Companion Objekt apply Unterschrift Teil der abstrakten Klasse zu machen? Oder gibt es einen anderen, besseren Ansatz?

Antwort

1

Da die Instanzen in Ihrer Karte tatsächlich das compaion Objekt sein woud, coul Sie die Begleiter Objekte aus Function1 erben lassen z.B .:

object LengthProvider extends ((DB) => LengthProvider) { 
    def apply(v1: DB): LengthProvider = new LengthProvider(v1) 
} 

object WidthProvider extends ((DB) => WidthProvider) { 
def apply(v1: DB): WidthProvider = new WidthProvider(v1) 
} 

val providers: Map[String, ((DB) => FieldProvider)] = Map(
    "length" -> LengthProvider, 
    "width" -> WidthProvider 
) 
+0

Dieses gut funktioniert! Jetzt habe ich ein Problem, dass "LengthProvider" tatsächlich ein implizites Argument benötigt. Kann es irgendwie durch diese 'apply'-Methode in Companion-Objekten weiterleiten? –