You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Dagger多绑定(Multibindings)指定顺序?

如何为Dagger多绑定(Multibindings)指定顺序?

我完全懂你的困扰——用Dagger的@IntoSet做多绑定时,默认是没法直接控制元素顺序的,就像你例子里想先喂山羊再喂牛,直接用Set确实做不到,而且用IntoMap加数字键又感觉不够优雅,毕竟Spring里有现成的排序注解可以用。

先回顾下你的场景代码,方便大家理解问题:

首先是需要注入Set的Farm类:

class Farm @Inject constructor(
    private val animals: Set<@JvmSuppressWildcards Animal>,
){
    
    init {
        animals.forEach { feed(it) }
    }
}

然后是分模块的绑定:

//module A
@Binds
@IntoSet
abstract fun goat(goat: Goat): Animal

//module B
@Provides
@IntoSet
fun cow(): Animal = Cow(...)

接下来给你几个更优雅的解决方案,不用生硬地用int键的Map:


方案1:注入排序后的List(最灵活)

既然Set本身是无序的,我们可以让Dagger注入一个预先排序好的List,而不是直接注入Set。

首先定义一个自定义限定符来标识这个有序集合:

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class OrderedAnimals

然后提供一个被排序后的List实例:

@Provides
@OrderedAnimals
fun provideOrderedAnimals(animals: Set<@JvmSuppressWildcards Animal>): List<Animal> {
    // 在这里自定义排序逻辑,比如按类型优先级排序
    return animals.sortedBy {
        when (it) {
            is Goat -> 0  // 山羊优先级最高,排前面
            is Cow -> 1   // 牛次之
            else -> 2     // 其他动物排最后
        }
    }
}

最后修改Farm类,注入这个有序List:

class Farm @Inject constructor(
    @OrderedAnimals private val animals: List<Animal>,
){
    
    init {
        animals.forEach { feed(it) }
    }
}

这个方案的好处是完全解耦,不需要修改Animal的实现类,排序逻辑集中在Provider里,想调整顺序直接改这里就行。


方案2:带优先级注解的Map绑定(比纯int键更清晰)

如果你还是想用类似Spring排序注解的思路,可以给每个绑定加一个带优先级的限定符,然后用Map收集后排序。

首先定义两个注解:一个用于标记优先级,一个用于标识这个排序用的Map:

// 标记每个Animal的优先级
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class AnimalPriority(val value: Int)

// 标识用于排序的Map
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class PriorityKeyedAnimals

然后修改绑定代码,用@IntoMap结合优先级注解:

//module A - 山羊优先级设为0
@Binds
@IntoMap
@AnimalPriority(0)
@PriorityKeyedAnimals
abstract fun goat(goat: Goat): Animal

//module B - 牛优先级设为1
@Provides
@IntoMap
@AnimalPriority(1)
@PriorityKeyedAnimals
fun cow(): Animal = Cow(...)

接下来提供一个排序后的List:

@Provides
fun provideOrderedAnimals(
    @PriorityKeyedAnimals animalMap: Map<Int, @JvmSuppressWildcards Animal>
): List<Animal> {
    // 按优先级键排序后取值
    return animalMap.toSortedMap().values.toList()
}

最后Farm注入这个List即可。这个方案更贴近Spring排序注解的思路,优先级明确标注在绑定上,可读性更高。


方案3:让Animal实现Comparable接口(适合简单场景)

如果所有Animal的实现类都能统一排序逻辑,可以让它们实现Comparable接口,然后注入SortedSet:

// 山羊实现Comparable,排在牛前面
class Goat : Animal, Comparable<Animal> {
    override fun compareTo(other: Animal): Int {
        return if (other is Cow) -1 else 0
    }
}

// 牛实现Comparable,排在山羊后面
class Cow : Animal, Comparable<Animal> {
    override fun compareTo(other: Animal): Int {
        return if (other is Goat) 1 else 0
    }
}

然后修改Farm的注入类型:

class Farm @Inject constructor(
    private val animals: SortedSet<@JvmSuppressWildcards Animal>,
){
    
    init {
        animals.forEach { feed(it) }
    }
}

这个方案的优点是简洁,但缺点也很明显:排序逻辑耦合在Animal实现类里,如果后续要调整顺序或者新增Animal类型,都要修改实现类,灵活性较差,适合排序逻辑固定的简单场景。


备注:内容来源于stack exchange,提问作者Vlad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 08:54:35