I use the factory pattern with generics. The idea is to create the right implementation (BlockType1Impl
or BlockType2Impl
) depending on the type of A
which is a case class( BlockchainType1
or BlockchainType2
). I don't put any Type Bounds constraints.
After looking at this example on the apply
method with generic types
trait BlockTypeFactory[A]{
def findTransactions( blocks: Seq[A], address: String): Seq[TransactionResponse]
}
object BlockTypeFactory{
// I want this method to return the correct implementations
def getBlockExplorer[A](blockType: A): BlockTypeFactory[A] = {
blockType match {
case type1: BlockchainType1 => new BlockTypeFactory[BlockchainType1](new BlockType1Impl)
// error : Expression of type BlockTypeFactory[BlockType1Impl] doesn't conform with the expected type BlockTypeFactory[A]
case type2: BlockchainType2 => new BlockType2Impl
}
}
def apply[A](implicit ev: BlockTypeFactory[A],blockType: A):BlockTypeFactory[A] = ev
}
But I get an error about expected type . What is exactly wrong ?
class BlockType1Impl extends BlockTypeFactory[BlockchainType1]
class BlockType2Impl extends BlockTypeFactory[BlockchainType2]
case class BlockchainType1(...)
case class BlockchainType2(...)
Your code doesn't work because the compiler doesn't know where to get the implicit instances of BlockTypeFactory.
In order to achieve your goal you can use Type Classes.
This way is extensible, you can have more than one factory per class if you want (you need to play with implicits scope) and you can define standard factories for some types.
You can code implicit instances of your case classes inside BlockTypeFactory object, but this is the way it is usually done.
// your type class
trait BlockTypeFactory[A] {
def create:A
}
case class BlockchainType1()
object BlockchainType1 {
// type 1 impl
implicit val factory:BlockTypeFactory[BlockchainType1] = new BlockTypeFactory[BlockchainType1] {
def create: BlockchainType1 = BlockchainType1()
}
}
case class BlockchainType2()
object BlockchainType2 {
// type 2 impl
implicit val factory:BlockTypeFactory[BlockchainType2] = new BlockTypeFactory[BlockchainType2] {
def create: BlockchainType2 = BlockchainType2()
}
}
object BlockTypeFactory {
// get factory
def apply[A:BlockTypeFactory]:BlockTypeFactory[A] = implicitly[BlockTypeFactory[A]]
// or create
def create[A:BlockTypeFactory]:A = implicitly[BlockTypeFactory[A]].create
}
val instance1 = BlockTypeFactory[BlockchainType1].create
val instance2 = BlockTypeFactory.create[BlockchainType2]
This pattern is called Type Class, and it is used to get ad hoc polymorphism. In your example, you need a polymorphic method findTransactions for each class defined on BlockTypeFactory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With