case类使用抽象类型

时间:2018-03-17 01:25:23

标签: scala traits case-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特性下定义函数,但代码仍然有气味。

  1. 我需要为我添加的每个属性包含[T]三次
  2. 我需要显式添加属性名作为额外的函数来访问它,好像它只是case类中的一个字段。
  3. 现在初始化Title我需要写

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

    而不是

    Title(101L, "Title")
    

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

1 个答案:

答案 0 :(得分:3)

您不需要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值,但是如果您希望它们具有prop的不同名称,则可以将它们传递给Property构造函数作为prop值。

然后它可以用作

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
}

(其余部分相同)

此方法的优点是您可以使用顶级特征来引用任何属性,例如

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"