Scala反射创建的样例类如何解析Ad-hoc polymorphism对应的BlockProcessor
问题根因
你当前实现的Ad-hoc多态完全依赖编译期隐式解析,反射生成的实例静态类型是父类BlockInputRequest,编译器无法在编译阶段确定实际子类类型,自然找不到对应的BlockProcessor[T]隐式实例,导致扩展方法调用失败。
可行解决方案
方案1:实现运行时处理器分发器(最推荐,可维护性最高)
手动维护子类到对应处理器的映射表,运行时根据实例的实际Class匹配处理器,不需要依赖复杂的反射API,性能稳定且易扩展:
import scala.reflect.ClassTag import scala.concurrent.ExecutionContext import scala.concurrent.Future object BlockProcessorDispatcher { // 存储子类Class和对应处理器的映射 private var processors: Map[Class[_], BlockProcessor[_]] = Map.empty // 注册新处理器的通用方法 def register[T <: BlockInputRequest : ClassTag](processor: BlockProcessor[T]): Unit = { processors += (implicitly[ClassTag[T]].runtimeClass -> processor) } // 运行时分派执行 def process(block: BlockInputRequest, project: String, userEmail: String, empty: Boolean = false)(implicit ec: ExecutionContext): Future[Any] = { processors.get(block.getClass) match { case Some(processor) => // 映射表保证了类型对应,强转安全 processor.asInstanceOf[BlockProcessor[BlockInputRequest]].processBlock(block, project, userEmail, empty) case None => Future.failed(new IllegalArgumentException(s"未找到对应处理器:${block.getClass.getName}")) } } // 初始化时注册已有处理器,后续新增处理器只要加一行注册即可 register(StaticBlockInputProcessor) }
反射拿到实例后直接调用即可:
BlockProcessorDispatcher.process(block, "myProject", "user@example.com", false)
方案2:用已保存的Manifest动态查找隐式
如果你已经持久化了Manifest[I],可以配合Scala反射API动态查找隐式实例,缺点是兼容性差、性能低于方案1:
import scala.reflect.runtime.universe._ import scala.reflect.runtime.currentMirror def getProcessor[I <: BlockInputRequest](manifest: Manifest[I]): Option[BlockProcessor[I]] = { val typeTag = TypeTag(currentMirror, new TypeTagCreator { def apply[U <: scala.reflect.api.Universe with Singleton](m: scala.reflect.api.Mirror[U]): U#Type = manifest.runtimeClass.asInstanceOf[U#Type] }) implicit val tt = typeTag scala.util.Try(implicitly[BlockProcessor[I]]).toOption }
方案3:模式匹配兜底(仅适合处理器数量极少的场景)
如果处理器数量极少、后续扩展需求低,可以直接对实例做模式匹配手动分派,缺点是违反开闭原则,新增处理器就要修改匹配逻辑:
val result = block match { case s: StaticBlockInput => s.processBlock("myProject", "user@example.com", false) // 新增子类时新增对应case case _ => Future.failed(new IllegalArgumentException("不支持的输入类型")) }
内容的提问来源于stack exchange,提问作者Alex Z
相关产品推荐
相关产品推荐

