Home > Software engineering >  Correct way to approach splitting a trait
Correct way to approach splitting a trait

Time:02-10

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)
}
  • Related