简体   繁体   中英

Scala instantiate a Concrete Class From Generic Type

I have a trait which is generic and goes like this:

trait MyTrait[T] {
  def doSomething(elems: Seq[T])
}

I then have a object factory whose definition goes like this:

object MyTraitFactory {
  def apply[T](param1: Boolean, param2: Boolean): MyTrait[T] = {
    // based on the type of T, I would like to instantiate sub types
  }
}

I have come concrete implementations that are for example:

class MyStringTrait extends MyTrait[String]

class MyIntTrait extends MyTrait[Int]

I now need that magic bit that would look for the type in my object factory and instantiate the corresponding implementations. Any suggestions?

This can be solved in scala using an implicit typeclass. Create a factory trait with concrete implementations for each of your types:

object MyTraitFactory {

  def apply[T](param1: Boolean, param2: Boolean)(implicit factory: MyTraitCreator[T]): MyTrait[T] = {
    // call the typeclass create method
    factory.create(param1, param2)
  }

  // factory trait
  trait MyTraitCreator[T] {
    def create(param1: Boolean, param2: Boolean): MyTrait[T]
  }

  // provide an implicit factory object for the specific types:
  object MyTraitCreator {

    implicit object MyStringTraitCreator extends MyTraitCreator[String] {
      override def create(param1: Boolean, param2: Boolean): MyTrait[String] = {
        // create the String type here
        new MyStringTrait
      }
    }

    implicit object MyIntTraitCreator extends MyTraitCreator[Int] {
      override def create(param1: Boolean, param2: Boolean): MyTrait[Int] = {
        // create the Int type here
        new MyIntTrait
      }
    }
  }
}

Scala "hides" the typeclass using the implicit parameter. But for this to work, you have to ensure to keep the implicit factory objects somewhere the compiler looks for implicits (eg the companion object to MyTraitCreator as above). The pattern works just as well without the implicit but then needs the caller to supply the concrete factory on each call.

This solution includes a lot of boiler plate code but works statically at compile time and does not suffer from type erasure. It even comes with syntactic sugar in scala:

def apply[T: MyTraitCreator](param1: Boolean, param2: Boolean): MyTrait[T] = {
    // call the typeclass create method
    implicitly[MyTraitCreator[T]].factory.create(param1, param2)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM