在Scala中有一种方法可以从Case类的实例中引用Companion对象吗?

时间:2015-04-28 14:43:28

标签: scala inheritance

在我的具体案例中,我有一个(不断增长的)具有基本特征的案例类库(TKModel

然后我有一个抽象类(TKModelFactory[T <: TKModel]),它由所有伴随对象扩展。

所以我的伴侣对象本身都知道他们需要提供的“答案”的类型('T')以及他们通常“接受”常用实现方法的对象类型。 (如果我变得懒惰并剪切和粘贴大量代码来搜索并销毁这个以节省我的培根!)我确实在互联网上看到了警告但是任何形式的CompanionObject.method(caseClassInstance: CaseClass)都充满了“代码味”然而。不确定他们是否真的适用于Scala?

然而,似乎没有任何方法可以在抽象案例类(TKModel)中声明任何可以引用(在运行时)案例类的特定实例的正确伴随对象的内容。 这导致我必须在每个案例类中编写(和编辑)一些我想要标准的方法调用。

case class Track(id: Long, name: String, statusID: Long) extends TKModel

object Track extends TKModelFactory[Track]

我如何在TKModel中写一些内容,new Track(1, "x", 1).someMethod()实际上可以调用Track.objectMethod()

是的我可以在val CO = MyCompanionObject抽象类中编写implicit val CO: ???TKModel之类的内容,并使所有调用都挂在该值之上。试图找到使编译器为此感到高兴的任何咒语,但似乎是不可能的任务。因为我不能声明我不能在抽象类中的任何占位符方法中引用它。

是否有一种更优雅的方式来简单地获取对案例类伴随对象的引用?

我的具体问题,如上所述(但似乎尚未回答),是否有办法处理伴随对象和案例类的继承,并找到引用,以便我可以编码常见方法在抽象类中调用?

或者是否存在完全不同且更好的模型?

4 个答案:

答案 0 :(得分:1)

一个伴随对象无法访问该实例,但是没有理由这个case类没有一个方法可以调用该伴随对象。

case class Data(value: Int) {
  def add(data: Data) = Data.add(this,data)
}

object Data {
  def add(d1: Data, d2: Data): Data =  Data(d1.value + d2.value)
}

答案 1 :(得分:0)

这很难。但是,您可以在随播对象中创建隐式方法。无论何时你想从实例调用你的逻辑,只需触发隐式规则,隐式方法将实例化另一个类,它将调用你想要的任何逻辑。 我相信也可以通用的方式做到这一点。

答案 2 :(得分:0)

您可以通过在伴随对象扩展的顶级抽象类中定义隐式类来将此语法实现为扩展方法:

abstract class TKModelFactory[T <: TKModel] {
  def objectMethod(t: T)

  implicit class Syntax(t: T) {
    def someMethod() = objectMethod(t)
  }
}

new Track(1, "x", 1).someMethod()的来电将等同于Track.objectMethod(new Track(1, "x", 1))

答案 3 :(得分:0)

如果稍微更改TKModel,可以执行

abstract class TKModel[T <: TKModel] {
  ...
  def companion: TKModelFactory[T]
  def someMethod() = companion.objectMethod()
}

case class Track(id: Long, name: String, statusID: Long) extends TKModel[Track] {
  def companion = Track
}
object Track extends TKModelFactory[Track] {
  def objectMethod() = ...
}

这样您就需要在每个类中实现companion。您可以通过使用反射实现companion来避免这种情况,例如(未经测试)

lazy val companion: TKModelFactory[T] = {
  Class.forName(getClass.getName + "$").getField("MODULE$").
    get(null).asInstanceOf[TKModelFactory[T]]
}

val是为了避免重复的反射调用。