首页 > 解决方案 > 如何在干净的架构中执行请求链?

问题描述

在我们的例子中,我需要在应用程序启动时执行请求链,例如

  1. 应用程序需要通过 gis 或 IP 地址检索位置
  2. 通过 http 按位置请求服务器列表
  3. 从我们得到的服务器列表中的服务器请求远程配置

我为每个项目创建一个数据层

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...
         }
       }
     }
   }
}

我觉得太丑了

我可以通过刀柄注入来做到这一点,存储库返回一个 Flow 而不是一个挂起函数调用,


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()

但是如何在流链中实现取消/重试逻辑?或者让 ui 知道哪一步是错误的或卡住的?

标签: androidkotlinclean-architecture

解决方案


那这个呢:

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 
}

您允许每个案例返回一个结果,分别处理错误处理并提前返回以停止继续。显示区域之间的清晰流动,但不是回调地狱。


推荐阅读