Dagger2如何结合Multibinding多绑定使用AssistedInject辅助注入
你遇到的编译错误如下:
Invalid return type: PaymentProvider. An assisted factory's abstract method must return a type with an @AssistedInject-annotated constructor.
该报错来自Dagger2对@AssistedFactory的硬性校验规则:被@AssistedFactory注解的工厂接口,其抽象创建方法的返回值必须是标注了@AssistedInject构造器的具体实现类,不能是该类的父接口或抽象父类。
你之前的写法让各个支付实现类内部的@AssistedFactory直接继承自定义的PaymentProviderFactory,而这个公共工厂的create方法返回值是PaymentProvider接口,不符合上述校验规则,因此编译失败。
另外你最初的设计存在逻辑矛盾:PaymentProvider实例的创建依赖运行时才能获取的业务参数PaymentData,这类对象不可能在Dagger初始化组件、创建PaymentManager时就提供实例,必须通过工厂模式延迟到参数齐备的业务调用节点再创建。
核心思路是:不要让各实现类的@AssistedFactory直接继承公共工厂接口,通过Multibinding把不同类型的创建入口(无参实现的Provider、需要运行时参数的AssistedFactory)统一绑定到Map中,手动实现公共工厂逻辑完成实例调度。
1. 调整支付实现类定义
每个需要Assisted注入的实现类,其内部的@AssistedFactory只负责创建自身具体类型的实例,不要继承公共工厂接口;无运行时参数的实现类保持普通@Inject构造注入即可:
// 需要运行时PaymentData参数的PayPal实现 interface PaymentProvider { fun pay(amount: Double): Boolean } class PayPalPayment @AssistedInject constructor( private val payPalRepo: PayPalRepository, @Assisted private val paymentData: PaymentData ): PaymentProvider { // 仅返回自身具体类型,不继承公共工厂接口 @AssistedFactory interface Factory { fun create(paymentData: PaymentData): PayPalPayment } override fun pay(amount: Double): Boolean { // 支付业务逻辑 return true } } // 无运行时参数的信用卡支付实现 class CreditCardPayment @Inject constructor( private val creditCardPaymentRepo: CreditCardPaymentRepository ): PaymentProvider { override fun pay(amount: Double): Boolean { // 支付业务逻辑 return true } }
2. 定义多绑定注解与Module配置
首先定义MapKey和支付类型枚举:
enum class PaymentType { PAYPAL, CREDIT_CARD } @MapKey @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class PaymentProviderKey(val value: PaymentType)
在Dagger Module中完成多绑定,统一实现公共工厂:
@Module abstract class PaymentModule { // 绑定PayPal的AssistedFactory到多绑定Map @Binds @IntoMap @PaymentProviderKey(PaymentType.PAYPAL) abstract fun bindPayPalFactory(factory: PayPalPayment.Factory): Any // 绑定信用卡支付的Provider到多绑定Map @Binds @IntoMap @PaymentProviderKey(PaymentType.CREDIT_CARD) abstract fun bindCreditCardProvider(provider: Provider<CreditCardPayment>): Any companion object { // 实现公共支付工厂 @Provides fun providePaymentProviderFactory( factoryMap: Map<PaymentProviderKey, @JvmSuppressWildcards Any> ): PaymentProviderFactory { return object : PaymentProviderFactory { override fun create(type: PaymentType, paymentData: PaymentData? = null): PaymentProvider { val entry = factoryMap[PaymentProviderKey(type)] ?: throw IllegalArgumentException("未找到对应支付类型的实现: $type") return when(entry) { is PayPalPayment.Factory -> { val data = paymentData ?: throw IllegalArgumentException("PayPal支付必须传入业务参数") entry.create(data) } is Provider<*> -> entry.get() as PaymentProvider else -> throw IllegalStateException("支付类型绑定配置错误: $type") } } } } // 提供PaymentManager实例 @Provides fun providePaymentManager(factory: PaymentProviderFactory): PaymentManager { return PaymentManager(factory) } } }
3. 调整公共工厂与PaymentManager逻辑
公共工厂接口和PaymentManager调整为延迟创建实例的模式:
// 公共支付工厂接口 interface PaymentProviderFactory { fun create(type: PaymentType, paymentData: PaymentData? = null): PaymentProvider } class PaymentManager( private val paymentProviderFactory: PaymentProviderFactory ) { // 实际发起支付时,传入运行时获取的支付类型、金额、业务参数 fun pay(type: PaymentType, amount: Double, paymentData: PaymentData? = null): Boolean { val provider = paymentProviderFactory.create(type, paymentData) return provider.pay(amount) } }
- 完全符合Dagger2对AssistedInject的校验规则,无编译错误
- 所有支付实现类的依赖仍由Dagger统一管理,不需要手动传递依赖实例
- 新增支付方式时仅需在Module中添加一条绑定规则即可,PaymentManager逻辑无需修改,符合开闭原则
- 同时兼容普通注入的无参实现类、需要Assisted注入的带运行时参数实现类,统一调度逻辑无侵入
内容的提问来源于stack exchange,提问作者testivanivan

