【问题标题】:How to use a case classes when hierarchy is needed?需要层次结构时如何使用案例类?
【发布时间】:2012-05-18 07:17:25
【问题描述】:

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

  • 如果我将超类设为普通类而不是案例类 - 我将失去所有案例类的优点,例如 toString、equals、hashCode 方法等。
  • 如果我将其保留为案例类,我将打破不从案例类继承的规则。
  • 如果我在子类中使用组合 - 我必须编写大量方法并将它们重定向到另一个类 - 这意味着大量的工作并且会让人感觉不是 Scalaish。

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

【问题讨论】:

    标签: scala case-class


    【解决方案1】:

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

    sealed trait Parent {
      /* implement all common properties */
    }
    
    case class A extends Parent
    
    case class B extends Parent {
      /*add all stuff you want*/
    }
    

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

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

    编辑:正如 cmets 中所建议的,如果模式匹配中没有涵盖所有案例类,您可以密封特征以便在编译时出现异常。例如,在“Scala 编程”的第 15.5 章中进行了说明

    【讨论】:

    • 树的想法很好理解
    • 抽象类更适合这里
    【解决方案2】:

    用委托代替继承怎么样?

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

    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(_)) => ...
    }
    

    好处:(?)

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

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

    缺点:(?)

    • 也许PayloadXY 在你的情况下实际上是Something 的真正子类,我的意思是,在你的情况下,也许委派在语义上是错误的?

    • 你必须写something.payload.whatever 而不是简单的something.whatever(我想这可能是好是坏取决于你的具体情况?)

    【讨论】:

    • 另一个缺点:您将无法再在方法签名中谈论特定类型,它总是“某事”。
    【解决方案3】:

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

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

    它不会(完全)删除样板,但定义了您的案例类必须遵守的合同,同时不会丢失案例类功能集...

    【讨论】:

      猜你喜欢
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 2011-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多