如何在需要层次结构时使用案例类?

时间:2012-05-18 07:17:26

标签: scala case-class

我知道你不允许继承案例类,但是当你真的需要时你会怎么做?我们在层次结构中有两个类,它们都包含许多字段,我们需要能够创建两个类的实例。这是我的选择:

  • 如果我让超类成为普通的类而不是案例类 - 我会失去所有案例类的优点,例如toString,equals,hashCode方法等。
  • 如果我把它作为一个案例类,我就打破了不继承案例类的规则。
  • 如果我在子类中使用组合 - 我必须编写很多方法并将它们重定向到另一个类 - 这意味着很多工作并且会觉得非Scalaish。

我该怎么办?这不是一个常见的问题吗?

3 个答案:

答案 0 :(得分:10)

是的,这是一个经常出现的问题,我建议使用所有父属性创建一个特征,创建一个只实现它的案例类,然后再创建另一个具有更多属性的案例类。

sealed trait Parent {
  /* implement all common properties */
}

case class A extends Parent

case class B extends Parent {
  /*add all stuff you want*/
}

看到它的好方法是树,特征是节点,案例类是叶子。

您可以根据父母的需要使用特质或抽象类。但是,避免使用类,因为您可以创建它的实例,这不是很优雅。

编辑:正如评论中所建议的那样,如果并非所有案例类都包含在模式匹配中,您可以密封特征以便在编译时出现异常。例如,“Scala编程”第15.5章对此进行了解释

答案 1 :(得分:6)

如何用委托替换继承?

如果层次结构中的两个类有许多共享字段,那么委托可以减少样板代码的数量吗?像这样:

case class Something(aa: A, bb: B, cc: C, payload: Payload)

sealed abstract class Payload

case class PayloadX(xx: X) extends Payload
case class PayloadY(yy: Y) extends Payload

然后你会像这样创建Something个实例:

val sth1 = Something('aa', 'bb', 'cc', PayloadX('xx'))
val sth2 = Something('aa', 'bb', 'cc', PayloadY('yy'))

你可以进行模式匹配:

sth1 match {
  case Something(_, _, _, PayloadX(_)) => ...
  case Something(_, _, _, PayloadY(_)) => ...
}

好处:(?)

  • 当您声明 PayloadX PayloadY 时,您不必重复 Something 中的所有字段。

  • 当您创建Something(... Payload(..))的实例时,您可以在创建SomethingSomething(... PayloadX(..))时重复使用创建...PayloadY的代码。

缺点:(?)

  • 在您的案例中,PayloadXY实际上可能是Something的真正子类,我的意思是,在您的情况下,或许委托在语义上是错误的?

    < / LI>
  • 你必须写something.payload.whatever而不是something.whatever(我想根据你的具体情况,这可能是好还是坏?)

答案 2 :(得分:3)

我也探讨过这个问题,AFAIK,你得到的最好的是:

  

让每个案例类从定义抽象的共同特征扩展   每个案例类必须实现的属性

它不会删除样板(根本没有),但定义了你的案例类必须遵守的契约,同时不会丢失案例类功能集......