Scala 当需要层次结构时,如何使用案例类?

Scala 当需要层次结构时,如何使用案例类?,scala,case-class,Scala,Case Class,我知道您不允许从case类继承,但是当您确实需要继承时,您会怎么做?我们在一个层次结构中有两个类,都包含许多字段,我们需要能够创建这两个类的实例。以下是我的选择: 如果我将超级类变成一个普通类而不是case类,我将失去所有case类的优点,比如toString、equals、hashCode方法等 如果我将它作为一个case类保留,我将打破不从case类继承的规则 如果我在child类中使用composition,我将不得不编写大量的方法并将它们重定向到另一个类,这将意味着大量的工作,而且会让

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

  • 如果我将超级类变成一个普通类而不是case类,我将失去所有case类的优点,比如toString、equals、hashCode方法等
  • 如果我将它作为一个case类保留,我将打破不从case类继承的规则
  • 如果我在child类中使用composition,我将不得不编写大量的方法并将它们重定向到另一个类,这将意味着大量的工作,而且会让人觉得没有伸缩性

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

我也探讨了这个问题,好吧,你能得到的最好结果是:

让每个case类从定义抽象的公共特性扩展 每个case类必须实现的属性


它不会删除样板文件,但定义了您的案例类必须遵守的契约,同时不会丢失案例类功能集…

是的,这是一个经常出现的问题,我建议您创建一个包含所有父属性的特征,创建一个只实现它的case类,然后再创建一个继承它的case类,并具有更多属性

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

case class A extends Parent

case class B extends Parent {
  /*add all stuff you want*/
}
一个很好的方法是看它是一棵树,特征是节点,案例类是叶子

根据您对父类的需求,您可以使用trait或抽象类。但是,避免使用类,因为您将能够创建它的实例,这将是不优雅的


编辑:正如注释中所建议的那样,如果模式匹配中没有涵盖所有的案例类,那么您可以密封trait,以便在编译时出现异常。例如,在“Scala编程”的第15.5章中进行了解释。

用委托代替继承怎么样

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

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
然后你会创建一些类似这样的实例:

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时,您不必重复某些内容中的所有字段

  • 当您创建
    某物(…有效负载(…)
    的实例时,您可以重用创建
    某物的代码,无论是在创建
    某物(…PayloadX(…)
    还是
    …PayloadY

缺点:(?)

  • 在你的例子中,也许
    PayloadX
    Y
    实际上是
    某物的真正子类,我的意思是,在你的例子中,也许委托在语义上是错误的

  • 你必须写
    一些东西。有效载荷。随便什么
    ,而不是简单地写
    一些东西。随便什么(我想这可能是好的还是坏的,取决于你的具体情况?)


另一个缺点:您将无法再谈论方法签名中的特定类型,它将始终是“某物”。树的思想非常适合更好地理解抽象类