2017-02-23 2 views
1

Mein Modell sieht ungefähr so ​​aus:Fall Class Konstruktorparameter als Tupel geben

abstract class A(id:String, val time:Int) extends Ordered[A]{ 
    override def compare(that:TrackingEvent) = this.time.compare(that.time) 
} 

case class B(id:String, override val time: Int, x:Int, y:int) extends A(id,time) { 
    //some methods 
} 
// more Case Classes who inherit from A 

ich einige Daten von einer mongodb und speichern sie in einigen Fall-Klassen (jede Klasse erbt von A)

Was ich im Moment tun, ist dies:

val header = getHeader(doc) //doc => actual row, return: Tuple2(String,Int) 
val xy = getXYDatapoint(doc) // return: Tuple2(Int,Int) 
val b = B(header._1,header._2,xy._1,xy._2) 

Jede vererbte Fall Klasse die gleiche getHeader (doc) Funktion verwendet, um den Header zu bekommen. (Deshalb hat die abstrakte Klasse A die zwei Argumente)

Ich möchte, dass es schöner aussieht, damit ich einige Zeilen löschen kann.

Etwas wie:

val b = B(header+xy) 

Oder sonst etwas. Ich kann den ganzen Scala-Code ändern und für jede Hilfe öffnen würde es schöner aussehen zu lassen (ich in Scala bin neu)

ich mit unförmigem versucht, aber das hat nicht funktioniert:

import shapeless._ 
import syntax.std.tuple._ 

val header = getHeader(doc) 
val xy = getXY(doc) 
val param = header++xy 

val b = (B.apply _).tupled(param) // didn't work because param is of type prepend.Out 
val b = (B.apply _).tupled(("a",2,3,4)) // would work 

Wenn jemand kenne ein paar nette Tipps oder Tricks, die ich gerne hören würde. für den Fall, Klasse

Antwort

1

Sie waren wirklich nah dran; Sie müssen nur explizit sagen, dass Ihr beabsichtigter Typ ein Tupel ist. Hier ist ein allgemeines Beispiel für alle Bedürftigen:

import shapeless.syntax.std.tuple._ 

case class Test(a: Int, b: Int, c: String, d: Int) 

val tuple: (Int, Int, String, Int) = (1, 2) ++ ("a", 3) 

Test.tupled(tuple) // works 

Wenn ich jedoch hinzufügen, um Ihre Nutzung Fall könnte durch einige zusätzliche Modellierung vereinfacht werden. Dann würden Sie überhaupt nicht formlos brauchen. In letzter Zeit habe ich viele Leute gesehen, die die Fallkurse missbraucht haben. Sie sind als abstrakte Datentypen (ADT) gedacht, nicht Klassen im allgemeinen Sinn. Wenn Ihre Fallklasse Logik enthalten muss, ist es wahrscheinlich besser, sie zu einer Klasse zu machen.

Sie haben jedoch einen Anwendungsfall für Fallklassen. Warum erfassen Sie nicht die Informationen über Header und Datenpunkt in zwei separaten ADTs?

Hier ist der vollständige Code:

case class Header(id: String, time: Int) 
case class DataPoint(x: Int, y: Int) 

abstract class A(id: String, val time: Int) { 
    // whatever 
} 

class B(header: Header, dataPoint: DataPoint) extends A(header.id, header.time) { 
    // whatever 
} 

val dataPoint = DataPoint(1, 2) 
val header = Header("header", 42) 

val b = new B(header, dataPoint) 

Natürlich, wenn die Semantik der Klasse A ‚s Parameter id und time die aus dem Header ist, könnten Sie sogar A nur einen Parameter dauern: abstract class A(header: Header).

Ich persönlich denke, das ist sauber, klar und gut modelliert. Natürlich kann Ihre Meinung anders sein.:)

+0

Ich denke, dein zweiter Punkt ist wirklich interessant. Aber was ist, wenn Sie eine Klasse C haben, die ein Array nimmt, Klasse D, die 2 Strings braucht, ... würden Sie immer noch dasselbe tun? – Boendal

+0

Es kommt immer auf den Anwendungsfall an. Haben Sie C, D usw., jedes mit verschiedenen Datentypen, aber alle repräsentieren Header, oder sind es eine Menge von 'id's und' time's kommen aus verschiedenen Sachen (nicht nur Header)? BTW lasst uns die Diskussion hier nicht überstrapazieren :) Wir haben das Hauptproblem gelöst (Fallklasse <-> Tupel). Ich habe Ihnen einen Hinweis zum Design gegeben, aber für weitere Fragen können wir uns immer auf gitter oder irgendwo treffen, oder Sie können eine Folgefrage stellen. – slouc

+0

Wir können hier diskutieren, wenn Sie möchten: https://gitter.im/scala/scala – slouc

1

Sie eine andere Methode anwenden definieren könnte:

case class B(id: String, override val time: Int, x: Int, y: Int) extends A(id, time) 
object B { 
    def apply(header: (String, Int), coordinates: (Int, Int)): B = 
    B(header._1, header._2, coordinates._1, coordinates._2) 
} 

Jetzt können Sie es als verwenden:

val header = getHeader(doc) 
val coords = getXY(doc) 
val b = B(header, coords) 

Das ist schön, weil man mehr nicht tupled nennen müssen, Sie erstellen nur Ihre Instanzen mit der neuen Methode apply und übergeben direkt die Ergebnisse von getHeader und getXY.

Verwandte Themen