如何在干净的架构中执行请求链?

How to perform a request chains in clean architecture?

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

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

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

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 尽早停止继续。 显示区域之间的清晰流,但不是回调地狱。