我已经使用 Clean Architecture 构建了应用程序,现在我计划在其中添加网络层验证。
下面是我如何在我的应用程序中实现此功能的代码。
interface JokeApi {
@GET("joke/Any")
suspend fun getJoke(): Response<JokeResponseDto>
}
class JokeRepositoryImpl @Inject constructor(private val jokeApi: JokeApi) : JokeRepository {
override suspend fun getJoke(): NetworkResponse<JokeResponse> {
return handleApiResponse { jokeApi.getJoke() }
}
}
NetworkResponse<JokeResponseDto>
suspend fun <T> handleApiResponse(execute: suspend () -> Response<T>): NetworkResponse<T> {
return try {
val response = execute()
val body = response.body()
if (response.isSuccessful && body != null) {
NetworkResponse.Success(data = body)
} else {
NetworkResponse.Error(errorMessage = response.message())
}
} catch (exception: HttpException) {
NetworkResponse.Error(errorMessage = exception.localizedMessage)
} catch (throwable: Throwable) {
NetworkResponse.Exception(throwable = throwable)
}
}
sealed class NetworkResponse<T>(
val data: T? = null,
val errorMessage: String? = null,
val exception: Throwable? = null,
) {
class Success<T>(data: T) : NetworkResponse<T>(data = data)
class Error<T>(errorMessage: String?) : NetworkResponse<T>(errorMessage = errorMessage)
class Exception<T>(throwable: Throwable) : NetworkResponse<T>(exception = throwable)
}
这里的问题是,retrofit 返回
JokeResponseDto
响应对象,而 getJoke
的 JokeRepositoryImpl
函数期望 JokeResponse
在此代码中的情况下是有效的 mapping
功能缺失。
我自己尝试在handleApiResponse方法中添加映射,因为它是通用类型,所以没有太多考虑实现。
下面是我如何尝试将响应转换为另一个对象,仅包含必要的详细信息。
class JokeResponseMapper : Mapper<JokeResponseDto, JokeResponse> {
override fun mapFrom(from: JokeResponseDto): JokeResponse {
return JokeResponse(
error = from.error,
type = from.type.orEmpty(),
setUp = from.type,
joke = from.joke,
)
}
}
interface Mapper<F, T> {
fun mapFrom(from: F): T
}
任何有关代码的帮助将不胜感激。
您可以创建一个将响应对象映射到域模型的接口:
interface DomainModel<T> {
fun mapToDomain(): T
}
然后像这样更改handleApiResponse:
suspend fun <DomainModel> handleApiResponse(execute: suspend () -> Response<DomainModel>): NetworkResponse<DomainModel> {
return try {
val response = execute()
val body = response.body()
if (response.isSuccessful && body != null) {
NetworkResponse.Success(data = body.mapToDomain())
} else {
NetworkResponse.Error(errorMessage = response.message())
}
} catch (exception: HttpException) {
NetworkResponse.Error(errorMessage = exception.localizedMessage)
} catch (throwable: Throwable) {
NetworkResponse.Exception(throwable = throwable)
}
}
现在 JokeResponseDto 必须实现这个接口,并且您必须在其中实现 mapToDomain 函数。
例如:
class JokeResponseDto(
....
....
): DomainModel<JokeResponse> {
override fun mapToDomain(): JokeResponse {
return JokeResponse(
...
)
}