2016-04-18 3 views
2

Я пытаюсь реорганизовать некоторые модели у меня есть, что в настоящее время выглядит следующим образом:Наследование с компаньоном объектов

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 _) 
} 

к чему-то, что выглядит следующим образом:

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 
} 

Так что я могу сделать это:

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] 

Я хочу еи ery для определения неявного значения чтения, но я не уверен, как указать это в сопутствующем объекте абстрактного класса.

ответ

4

Не существует языковой функции, которая заставит абстрактную пару класса/компаньона быть расширенной вместе. Я преодолел это недостающее звено, сделав «компаньона» абстрактного класса чертой. Что-то вроде этого:

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] { 
    ... 
} 

К сожалению, это еще не говорит MyTrait (как определено в OP), что Model <: BaseModel есть компаньон, где неявное Reads[Model] можно найти. Опять же, связь должна быть сделана вручную, требуя, чтобы MyTrait содержал ссылку на сопутствующий объект модели.

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 
}