将多模块项目中的数据层和领域层分开,并遵循Solid中的D

问题描述 投票:0回答:1

我有一个多模块项目,我想在两个不同的模块中将数据和域逻辑彼此分离。 (目前它们都在核心模块中):https://github.com/alirezaeiii/TMDb-Compose-Playground

我的应用程序有一个支持不同屏幕分页的逻辑:

private const val STARTING_PAGE_INDEX = 1

abstract class BasePagingSource<T : TMDbItem>(private val context: Context) : PagingSource<Int, T>() {

    protected abstract suspend fun fetchItems(page: Int): List<T>

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, T> {
        val page = params.key ?: STARTING_PAGE_INDEX
        return try {
            val response = fetchItems(page)
            LoadResult.Page(
                data = response,
                prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1,
                nextKey = if (response.isEmpty()) null else page + 1
            )
        } catch (exception: IOException) {
            LoadResult.Error(TMDbException(context.getString(R.string.failed_loading_msg)))
        } catch (exception: HttpException) {
            LoadResult.Error(TMDbException(context.getString(R.string.failed_loading_msg)))
        }
    }

    override fun getRefreshKey(state: PagingState<Int, T>): Int? {
        return state.anchorPosition?.let {
            state.closestPageToPosition(it)?.prevKey?.plus(1)
                ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
        }
    }
}

我有一个基本存储库类:

abstract class BasePagingRepository<T : TMDbItem> {

    protected abstract fun pagingSource(query: String?): BasePagingSource<T>

    fun fetchResultStream(query: String?= null): Flow<PagingData<T>> = Pager(
        config = PagingConfig(pageSize = NETWORK_PAGE_SIZE),
        pagingSourceFactory = { pagingSource(query) }
    ).flow

    companion object {
        private const val NETWORK_PAGE_SIZE = 20
    }
}

这种方法的问题是所有子类都以相同的方式扩展它:

@Singleton
class AiringTodayTvSeriesPagingRepository @Inject constructor(
    @ApplicationContext private val context: Context,
    private val tvShowApi: TVShowService
) : BasePagingRepository<TVShow>() {

    override fun pagingSource(query: String?): BasePagingSource<TVShow> =
        AiringTodayTvSeriesPagingSource(context, tvShowApi)
}

或者:

@Singleton
class OnTheAirTvSeriesPagingRepository @Inject constructor(
    @ApplicationContext private val context: Context,
    private val tvShowApi: TVShowService
) : BasePagingRepository<TVShow>() {

    override fun pagingSource(query: String?): BasePagingSource<TVShow> =
        OnTheAirTvSeriesPagingSource(context, tvShowApi)
}

核心模块中的 com.sample.tmdb.core.data.repository 包中的等。例如,它们都扩展了

BasePagingRepository<TVShow>
。当然,我已经对存储库使用了依赖注入:

    @Singleton
    @Binds
    internal abstract fun bindTrendingTVShowRepository(trendingTvSeriesPagingRepository: TrendingTvSeriesPagingRepository): BasePagingRepository<TVShow>

    @Singleton
    @Binds
    internal abstract fun bindPopularTVShowRepository(popularTvSeriesPagingRepository: PopularTvSeriesPagingRepository): BasePagingRepository<TVShow>

    @Singleton
    @Binds
    internal abstract fun bindAiringTodayTVShowRepository(airingTodayTvSeriesPagingRepository: AiringTodayTvSeriesPagingRepository): BasePagingRepository<TVShow>

    @Singleton
    @Binds
    internal abstract fun bindOnTheAirTVShowRepository(onTheAirTvSeriesPagingRepository: OnTheAirTvSeriesPagingRepository): BasePagingRepository<TVShow>

因此,当我想将这些存储库注入到我的 ViewModel 中时,我必须使用具体实现而不是抽象或接口(Solid 中的

Dependency inversion
),例如:

@HiltViewModel
class AiringTodayTvSeriesViewModel @Inject constructor(repository: AiringTodayTvSeriesPagingRepository) :
    BaseMainPagingViewModel<TVShow>(repository)

因此,第一,我没有遵循依赖关系倒置,第二,我必须将

data
domain
模块依赖项添加到我的功能模块中。我认为这不太好,只需添加
domain
依赖项就足够了,因为我的界面和抽象存储库都在那里。

您如何解决这个问题?我很感激任何建议。

android solid-principles clean-architecture multi-module dependency-inversion
1个回答
0
投票

我在使用 Hilt 时决定使用限定符注释来实现此目的,例如:

@Retention(AnnotationRetention.BINARY)
@Qualifier
annotation class Discover

在di模块中,我使用它如下:

    @Singleton
    @Discover
    @Binds
    internal abstract fun bindDiscoverMoviesRepository(discoverMoviesPagingRepository: DiscoverMoviesPagingRepository): BasePagingRepository<Movie>

我只是在 ViewModel 中使用了注释:

@HiltViewModel
class DiscoverMoviesViewModel @Inject constructor(
    @Discover repository: BasePagingRepository<Movie>
) : BaseMainPagingViewModel<Movie>(repository)
© www.soinside.com 2019 - 2024. All rights reserved.