2016-04-18 9 views
2

ich einige Modelle Refactoring versuche ich habe zur Zeit das wie folgt aussehen:Vererbung mit Begleiter Objekte

case class Person(name: String, age: Int) 

object Person { 
    implicit val reads: Reads[Person] = (
     (JsPath \ "name").read[String] and 
     (JsPath \ "age").read[Int] 
    )(Person.apply _) 
} 

Um etwas, das wie folgt aussieht:

abstract class BaseModel { 
    val pk: String // Some stuff here that will be common 
} 

object BaseModel { 
    implicit val reads: Reads[BaseModel] // Not sure what to do here 
} 

Damit ich dies tun können:

trait MyTrait[Model <: BaseModel] { 

    // More code here 
    val body: JsObject = ... 
    val parsed = body.validate[Model] // Error: There is no implicit value defined for Model 

} 


case class NewPerson extends BaseModel {...} 
object NewPerson {...} // Maybe need to extend something here 


class MyController extends MyTrait[NewPerson] 

ich möchte ev Ery-Modell, um einen impliziten Lesewert zu definieren, aber ich weiß nicht, wie ich dies im Companion-Objekt der abstrakten Klasse angeben soll.

Antwort

4

Es gibt kein Sprachfeature, das die Erweiterung einer abstrakten Klasse/eines Companion-Paars erzwingt. Ich habe dieses fehlende Glied überwunden, indem ich den "Gefährten" der abstrakten Klasse zu einem Merkmal gemacht habe. Etwas wie folgt aus:

abstract class BaseModel { 
    val pk: String 
} 

trait ModelCompanion[A <: BaseModel] { self: Singleton => 
    implicit val reads: Reads[A] 
} 

case class Person(name: String, age: Int) extends BaseModel 

object Person extends BaseModel[Person] { 
    ... 
} 

Leider ist dies noch nicht MyTrait nicht sagen (wie im OP definiert), dass ein Model <: BaseModel einen Begleiter hat, wo eine implizite Reads[Model] gefunden werden kann. Auch hier muss die Verbindung manuell hergestellt werden, indem MyTrait erforderlich ist, um einen Verweis auf das Companion-Objekt des Modells zu halten.

trait MyTrait[Model <: BaseModel] { 

    def companion: ModelCompanion[Model] 

    implicit def reads: Reads[Model] = companion.reads 

    // More code here 
    val body: JsObject = ... 
    val parsed = body.validate[Model] // Now this would work 

} 

object MyTraitImpl extends MyTrait[Person] { 
    def companion = Person 
}