Scala泛型工厂模式实现类型安全支付服务的编译问题排查
问题根本原因
getService方法的返回类型推导限制:你根据字符串匹配返回两种不同的Service实现,编译器只能推导返回类型为Service[_ >: CreditCardTransaction with BankTransaction <: Transaction],这里的通配符_代表未知的Transaction子类型,编译器无法确认这个未知类型和后续Parser返回的Transaction实例是对应的,所以调用transfer时会报类型不匹配:方法要求的参数是那个未知的_$1类型,但你传入的是父类Transaction,类型不兼容。- 泛型擦除导致匹配失效:你在Parser里对
Service[T]的模式匹配是无效的,JVM运行时会擦除泛型参数信息,Service[CreditCardTransaction]和Service[BankTransaction]运行时都是Service类型,模式匹配会直接命中第一个case,哪怕你传入的是TTService,也会返回CreditCardTransaction,运行时会报类转换异常。
可行的修复方案
方案1:将服务和交易解析逻辑绑定,消除类型不匹配的可能
直接把对应交易的构造逻辑封装到Service内部,这样拿到服务实例就能直接生成对应类型的交易,不需要外部Parser做匹配,从根源上避免类型错位:
trait Service[T <: Transaction] { def transfer(transaction: T): Unit // 新增交易构造方法,每个实现类返回自己对应的交易类型 def buildTransaction(): T // 新增通用执行入口,内部保证类型匹配,控制层无需感知泛型 def execute(): Unit = transfer(buildTransaction()) } class CCService() extends Service[CreditCardTransaction] { override def transfer(transaction: CreditCardTransaction): Unit = println("pay with cc") override def buildTransaction(): CreditCardTransaction = CreditCardTransaction(100, "Name", "01/01") } class TTService() extends Service[BankTransaction] { override def transfer(transaction: BankTransaction): Unit = println("pay with telex transfer") override def buildTransaction(): BankTransaction = BankTransaction(100, "1234") }
调用处直接调用统一入口即可:
object App { val factory = new PaymentSystemFactory(new CCService, new TTService) val service = factory.getService("cc") service.execute() // 编译通过,类型安全 }
方案2:用TypeTag保留泛型信息,实现类型安全匹配
如果不想把解析逻辑放到Service里,可以用Scala的TypeTag机制保留泛型参数信息,解决擦除问题,同时用存在类型绑定保证服务和交易的类型匹配:
import scala.reflect.runtime.universe._ trait Service[T <: Transaction] { def transfer(transaction: T): Unit // 保留泛型类型标签 def ttag: TypeTag[T] } class CCService() extends Service[CreditCardTransaction] { override def transfer(transaction: CreditCardTransaction): Unit = println("pay with cc") override val ttag: TypeTag[CreditCardTransaction] = typeTag[CreditCardTransaction] } class TTService() extends Service[BankTransaction] { override def transfer(transaction: BankTransaction): Unit = println("pay with telex transfer") override val ttag: TypeTag[BankTransaction] = typeTag[BankTransaction] } object Parser { def parse[T <: Transaction](service: Service[T]): T = service.ttag.tpe match { case t if t =:= typeOf[CreditCardTransaction] => CreditCardTransaction(100, "Name", "01/01").asInstanceOf[T] case t if t =:= typeOf[BankTransaction] => BankTransaction(100, "1234").asInstanceOf[T] } } // 调用处用类型绑定保证匹配 object App { val factory = new PaymentSystemFactory(new CCService, new TTService) val service = factory.getService("cc") val transaction = Parser.parse(service) service.transfer(transaction) // 编译通过 }
内容的提问来源于stack exchange,提问作者Alexander Nekrasov
相关产品推荐
相关产品推荐

