与伴随对象的继承

时间:2016-04-18 02:15:47

标签: scala generics inheritance companion-object

我正在尝试重构一些目前看起来像这样的模型:

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]

我希望每个模型都定义一个隐式读取值,但我不确定如何在抽象类的伴随对象中指明它。

1 个答案:

答案 0 :(得分: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
}