I want to use Factory Method with Generics which can work with specific implementations. In service classes i want to have type safety but in controller to operate only know interface.
Code
I have defined different types of operation type
trait Transaction {
val amount: BigDecimal
}
case class CreditCardTransaction(amount: BigDecimal, ccNumber: String, expiry: String) extends Transaction
case class BankTransaction(amount: BigDecimal, bankAccount: String) extends Transaction
and Services which can work with specific operation types
trait Service[T <: Transaction] {
def transfer(transaction: T)
}
class CCService() extends Service[CreditCardTransaction] {
override def transfer(transaction: CreditCardTransaction): Unit = println("pay with cc")
}
class TTService() extends Service[BankTransaction] {
override def transfer(transaction: BankTransaction): Unit = println("pay with telex transfer")
}
I have created factory with concrete instances
class PaymentSystemFactory(ccService: CCService, ttService: TTService) {
def getService(paymentMethod: String) = paymentMethod match {
case "cc" => ccService
case "tt" => ttService
}
}
And parser to get specific transaction from external service
object Parser {
def parse(service: Service[_ <: Transaction]) = service match {
case _: Service[CreditCardTransaction] => CreditCardTransaction(100, "Name", "01/01")
case _: Service[BankTransaction] => BankTransaction(100, "1234")
}
}
But that code doesn't want to compile due provided types mismatch from PaymentSystemFactory method:
object App {
val factory = new PaymentSystemFactory(new CCService, new TTService)
val service = factory.getService("cc") // return Service[_ >: CreditCardTransaction with BankTransaction <: Transaction]
val transaction: Transaction = Parser.parse(service)
service.transfer(transaction) // Failed here: Required _$1 found Transaction
}
I would be happy to avoid type erasure if possible due factory method call and wondered why that code doesn't work