I have 3 traits:
trait Worker
...
trait StringWorker extends Worker {
def workString(): Iterator[String]
}
...
trait IntWorker extends Worker {
def workInt(): Iterator[Int]
}
Some of my classes extend only StringWorker
, while others extend both StringWorker
and IntWorker
My code obtains the correct parser depending on some pattern matching like so:
def getCorrectWorkerProvider: () => Worker = {
case SomeCase => getStringWorkerProvider()
case _ => getIntWorkerProvider()
}
If I keep the traits the same as written above, then I'll pretty much always have to do something like this pseudocode:
if working with string, then getCorrectWorkerProvider().asInstanceOf[StringWorker].workString
if working with int, then getCorrectWorkerProvider().asInstanceOf[IntWorker].workInt
whereas if I changed the definition of the traits to something like this:
trait Worker {
def workString(): Iterator[String]
def workInt(): Iterator[Int]
}
trait StringWorker extends Worker
trait IntWorker extends Worker
then I would never have to use .asInstanceOf[SomeWorker]
to invoke the correct method.
I believe the first way is more correct and intuitive as the methods are specific to a certain Worker, but the second way seems to be less of a headache.
CodePudding user response:
Basically, what you're looking for is called the typeclass pattern. Here's an article that explains the idea. Basically the way it works if you create a function that takes an implicit parameter, and then you use scala's implicit resolution mechanism to find the right "worker".
Here's an example:
object Main {
def main(args: Array[String]): Unit = {
work("String")
work(3)
}
def work[T](value: T)(implicit worker: Worker[T]) = {
worker.work(value)
}
}
trait Worker[T]{
def work(t: T): Iterator[T]
}
object Worker {
implicit val stringWorker: Worker[String] = (t: String) => Iterator(t)
implicit val intWorker: Worker[Int] = (t: Int) => Iterator(t)
}