如何在干净的架构中执行请求链?
How to perform a request chains in clean architecture?
在我们的例子中,我需要在应用程序启动时执行请求链,例如
- 应用程序需要通过 gis 或 IP 地址检索位置
- 通过 http
按位置请求服务器列表
- 从服务器列表中我们得到的服务器请求远程配置
我为每个项目创建一个数据层
class DefaultLocationRepository(
@LocateByGis gisLocationDataSource: LocationDataSource,
@LocateByIp ipLocationDataSource: LocationDataSource
): LocationRepository {
suspend fun locate(): Result<Location> {
....
}
}
class DefaultServerRepository(
remoteServerDataSource: RemoteServerDataSource
): ServerRepository {
suspend fun retrieve(location: Location): List<Server> {
}
}
class DefaultRemoteConfigRepository (
remoteConfigDataSource: RemoteConfigDataSource
): RemoteConfigDataSource {
suspend fun retrieve(server: List<Server>) {
}
}
我的问题是,链接这些任务的最佳做法是什么?
我可以为每个动作制作一个用例
class LocateUseCase
class RetrieveServersUseCase
class RetrieveRemoteConfigUseCase
class MainViewModel: ViewModel() {
suspend fun start() {
locateUserCase().onSuccess {
retrieveServerUseCase(GetLocationUseCase()).onSuccess {
retrieveConfigServerUseCase(GetServerListUseCase()).onSuccess {
// balabala...
}
}
}
}
}
我觉得太丑了
我可以通过 hilt 注入来完成,存储库 returns 一个流而不是挂起函数调用,
class LocatonRepository() {
private var latestLocation: Location? = null
val location: Flow<Location> {
if (latestLocation != null) {
emit (latestLocation!!)
return@flow
}
dataSource.get().onSuccess { emit(it) }
}
}
// Modules
@InstallIn(Singleton::class::java)
@Module
class Modules {
@Provides
fun provideLocation(repository: LocationRepository): Flow<Location> =
repository.location
}
当 Flow 注入到 ServerList 时,服务器存储库可以通过 location.first()
触发定位请求
但是如何在流链中实现cancel/retry逻辑呢?或者让 ui 知道哪一步错误或卡住了?
这个怎么样:
suspend fun start() {
val locationResult = locateUserCase()
if(locationResult.isFailure()) {
// do location error handling
return
}
val location = locationResult.getOrThrow()
val serverResult = retrieveServerUseCase(location)
if(serverResult.isFailure()) {
// do server error handling
return
}
val server = serverResult.getOrThrow()
val configResult = retrieveConfigServerUseCase(server)
if(configResult.isFailure()) {
// do config error handling
return
}
// do total success handling
}
您允许每个案例 return 一个结果,分别处理错误并 return 尽早停止继续。
显示区域之间的清晰流,但不是回调地狱。
在我们的例子中,我需要在应用程序启动时执行请求链,例如
- 应用程序需要通过 gis 或 IP 地址检索位置
- 通过 http 按位置请求服务器列表
- 从服务器列表中我们得到的服务器请求远程配置
我为每个项目创建一个数据层
class DefaultLocationRepository(
@LocateByGis gisLocationDataSource: LocationDataSource,
@LocateByIp ipLocationDataSource: LocationDataSource
): LocationRepository {
suspend fun locate(): Result<Location> {
....
}
}
class DefaultServerRepository(
remoteServerDataSource: RemoteServerDataSource
): ServerRepository {
suspend fun retrieve(location: Location): List<Server> {
}
}
class DefaultRemoteConfigRepository (
remoteConfigDataSource: RemoteConfigDataSource
): RemoteConfigDataSource {
suspend fun retrieve(server: List<Server>) {
}
}
我的问题是,链接这些任务的最佳做法是什么? 我可以为每个动作制作一个用例
class LocateUseCase
class RetrieveServersUseCase
class RetrieveRemoteConfigUseCase
class MainViewModel: ViewModel() {
suspend fun start() {
locateUserCase().onSuccess {
retrieveServerUseCase(GetLocationUseCase()).onSuccess {
retrieveConfigServerUseCase(GetServerListUseCase()).onSuccess {
// balabala...
}
}
}
}
}
我觉得太丑了
我可以通过 hilt 注入来完成,存储库 returns 一个流而不是挂起函数调用,
class LocatonRepository() {
private var latestLocation: Location? = null
val location: Flow<Location> {
if (latestLocation != null) {
emit (latestLocation!!)
return@flow
}
dataSource.get().onSuccess { emit(it) }
}
}
// Modules
@InstallIn(Singleton::class::java)
@Module
class Modules {
@Provides
fun provideLocation(repository: LocationRepository): Flow<Location> =
repository.location
}
当 Flow 注入到 ServerList 时,服务器存储库可以通过 location.first()
但是如何在流链中实现cancel/retry逻辑呢?或者让 ui 知道哪一步错误或卡住了?
这个怎么样:
suspend fun start() {
val locationResult = locateUserCase()
if(locationResult.isFailure()) {
// do location error handling
return
}
val location = locationResult.getOrThrow()
val serverResult = retrieveServerUseCase(location)
if(serverResult.isFailure()) {
// do server error handling
return
}
val server = serverResult.getOrThrow()
val configResult = retrieveConfigServerUseCase(server)
if(configResult.isFailure()) {
// do config error handling
return
}
// do total success handling
}
您允许每个案例 return 一个结果,分别处理错误并 return 尽早停止继续。 显示区域之间的清晰流,但不是回调地狱。