case class 用抽象类型扩展特征

case class extending trait with abstract type

我有几个这样的案例 class:

case class Size(id: Long, size: Int)

case class Title(id: Long, title: String)
.
.
.

我喜欢其中的 10 个,功能几乎相同。我决定将它们结合在一个共同的特征下,这导致了这样的事情:

trait Property[T]{
    val value: T
}

trait PropertyPair[T]{
   val id: Long
   val prop: Property[T]
}

case class Size(id: Long, prop: Property[Int]) extends PropertyPair[Int] {
    def size: Int = prop.value
}

case class Title(id: Long, prop: Property[String]) extends PropertyPair[String] {
    def title: String = prop.value
} 

虽然上面的代码块似乎是一个很好的解决方案,现在我实际上可以在 PropertyPair trait 下定义函数,但代码仍然有味道。

  1. 我需要为每个 属性 添加三次 [T] 我添加
  2. 我需要显式添加 属性 名称作为额外函数来访问它,就好像在 class.
  3. 情况下它只是一个字段一样

现在初始化Title我需要写

Title(101L, Property("Title")) 

而不是

Title(101L, "Title")

出于某种原因,我确信有比我提供的解决方案更优雅、更不容易出错的解决方案。

您不需要 2 个级别,可以将 trait 替换为 abstract class 以利用其构造函数:

sealed abstract class Property[T](val prop: T) {
  val id: Long
}

case class Size(id: Long, size: Int) extends Property[Int](size)
case class Title(id: Long, title: String) extends Property[String](title)

这些案例中的每一个都有一个 id 值,这是 Property class 所要求的,但是由于您希望它们对 prop 具有不同的名称,您可以将它们作为 prop 值传递给 Property 构造函数。

那么可以作为

val size = Size(101L, 42)
val title = Title(202L, "Foo")

这是一个简单的解决方案。对于更一般的情况,我建议您这样做:

sealed trait AnyProperty {
  val id: Long

  type Prop
  val prop: Prop
}

sealed abstract class Property[T](
  val prop: T
) extends AnyProperty {
  type Prop = T
}

(其余同)

这种方式的优点是可以使用top trait来引用any 属性,例如

def foo[P <: AnyProperty](p: P): Long = p.id
foo(size) // 101L

的可以参考Prop类型的成员,例如

def buh[P <: AnyProperty](p: P): P#Prop = p.prop
buh(title) // "Foo"