Reputation: 77
I had a couple of case classes like that:
case class Size(id: Long, size: Int)
case class Title(id: Long, title: String)
.
.
.
I had like 10 of these with pretty much the same functions. I decided to combine them under a common trait, which led to something like this:
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
}
Though the code block above seems to be a good solution, and now I can actually define functions under the PropertyPair
trait, but the code still smells.
[T]
three times for every property I add Now to initialize Title
i need to write
Title(101L, Property("Title"))
instead of
Title(101L, "Title")
For some reason I am sure there is a much more elegant and less error-prone solution then the one I provided.
Upvotes: 1
Views: 1302
Reputation: 6460
You don't need 2 levels and can replace trait
with abstract class
to make use of its constructor:
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)
Each of these cases has an id
value which is required by the Property
class, but as you want them to have different names for prop
, you can just pass them to the Property
constructor as the prop
value.
Then it can be used as
val size = Size(101L, 42)
val title = Title(202L, "Foo")
This is a straightforward solution. For a more general case I would suggest you to do it like this:
sealed trait AnyProperty {
val id: Long
type Prop
val prop: Prop
}
sealed abstract class Property[T](
val prop: T
) extends AnyProperty {
type Prop = T
}
(the rest is the same)
Advantages of this approach are that you can use the top trait to refer to any property, for example
def foo[P <: AnyProperty](p: P): Long = p.id
foo(size) // 101L
Of you can refer to the Prop
type member, for example
def buh[P <: AnyProperty](p: P): P#Prop = p.prop
buh(title) // "Foo"
Upvotes: 3