【问题标题】:Scala: Using Trait + Companion object to enumerate implementationsScala:使用 Trait + Companion 对象枚举实现
【发布时间】:2019-05-16 21:36:57
【问题描述】:

我的问题是:这是一个反模式吗:

我有一个密封的 scala 特征,有十几个或两个实现 - 可以这样说:

package com.erik.logic

sealed trait FailureReason {
  def why: String
}

case object A extends FailureReason {
  val why = "just because"
}
case class B(why: String) extends FailureReason
// ...
case object Z extends FailureReason {
  val why = "idk"
}

Imports 会变得丑陋(或 6 以上,根据我读过的大多数样式指南,开始使用 ._ 样式)。

一种选择是将它们全部放在特征的伴随对象中,然后我可以以类似于枚举的方式导入和引用它。 这是一种反模式吗?

package com.erik.logic

trait FailureReason {
  def why: String
}

object FailureReason
  case object A extends FailureReason { ... }
  case class B(why: String) extends FailureReason
  // ...
}

// otherFile.scala
import com.erik.logic.FailureReason

... reason match {
  case FailureReason.A => something
  case FailureReason.B(y) => other(y)
  case FailureReason.C => etc
}


// yetAnotherFile.scala
import com.erik.logic.FailureReason.{A, B, J, Q}

// ... badThing match {
  case SomethingBad => ReasonWrapper(A)
  case SomethingTerrible => ReasonWrapper(B("terrible"))
  case SomethingMeh => ReasonWrapper(Q)
}

【问题讨论】:

  • 我不认为这是一个反模式,我用过几次。我还看到它在其他项目中使用,例如Scapegoat。不过有one point against it,不过是和java序列化有关的,如果不需要的话应该问题不大。 - 无论如何,这可能会以意见为基础。
  • 关于序列化的那一点不太正确。它说“不要在另一个类/对象中声明案例类”,但这解释了你不应该如何在一个包含大量其他数据的对象中声明案例类,这不是一回事.
  • @Dima 只是为了好奇,问题还是一样的,对吧?如果你在一个对象内部定义了case类,那么如果你需要序列化这样的case类,它也必须序列化对象(因此,所有case类的定义),或者不是? - 我有点感兴趣,因为一所大学告诉我,在几天前的一次审查中,我在另一个对象内部的一个对象中定义了几个案例类,只是为了避免创建几个文件夹,所以我想知道是否这确实是个问题(然而,我们并不真正关心 java 序列化)
  • @LuisMiguelMejíaSuárez 序列化不序列化定义。只有数据。
  • @Dima OK,因此它只需要序列化对父对象的引用,这还不错。谢谢。

标签: scala


【解决方案1】:

这不是“反模式”,没关系。您可以顺便说一句,在包级别以相同的方式导入:import com.erik.logic.{A, B, J, Q},因此无需将它们放入对象中出于这个原因(但没有任何问题也可以,如果你想这样做的话)。

请注意,您可能应该将您的特质设为sealed。这样,如果您忘记了一些 case 子句,您可以利用编译器警告您,而您的 match 并不详尽。

【讨论】:

  • 嗨,只是好奇,真的有必要extendstrait吗?换句话说,如果它不像 Spark 源代码中的 this example 那样 extendstrait 有什么好处?谢谢。
  • @jack 扩展特征的原因是您可以在其他地方引用它。如果你有一个sealed trait Foo,以及一堆扩展它的实现,然后你创建了一个像def foo(bar: Foo) 这样的函数,你可以确定可以传入的bar 始终是这些类型之一。
  • 谢谢。只是想明白,在这个example里,所有的case objects都不是extendingMasterMessages ,那有sealed trait MasterMessages有什么意义呢?
  • 是的,我不知道。我认为拥有它没有任何意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多