我有几个这样的案例类:
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
特性下定义函数,但代码仍然有气味。
[T]
三次现在初始化Title
我需要写
Title(101L, Property("Title"))
而不是
Title(101L, "Title")
出于某种原因,我确信有一个更优雅,更不容易出错的解决方案,而不是我提供的解决方案。
答案 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"