因此,我正在重写应用程序的代码,使其“干净”(按照Android团队推荐的MVVM模式,进行层分离)
在这里,我有一个简单的Retrofit接口可以与我的API通信
interface Api {
@GET("comments")
suspend fun getPlaceComments(@Query("placeId") placeId: String): Response<List<CommentResponse>>
@POST("comments")
suspend fun addPlaceComment(@Header("placeId") placeId: String, @Header("text") text: String): Response<Unit>
@DELETE("comments")
suspend fun deletePlaceComment(@Header("placeId") placeId: String): Response<Unit>
}
只是一个简单的CRUD。
现在,向上一层,我有了我的SocialRepository。为了避免代码重复,我创建了通用方法callSafely
,该方法将一个正在挂起的API函数和一个placeId作为其参数。
class SocialRepository {
private val client: Api = ApiClient.webservice
private suspend fun <T> callSafely(
apiMethod: suspend (placeId: String) -> Response<T>,
placeId: String,
): T? {
Log.d(TAG, "$apiMethod called safely")
var response: Response<T>? = null
try {
response = apiMethod(placeId)
} catch (e: Exception) {
e.printStackTrace()
}
if (response?.isSuccessful != true) {
Log.w(TAG, "response.isSuccessful isn't true.")
}
return response?.body()
}
suspend fun getPlaceComments(placeId: String): List<CommentResponse>? {
return callSafely(client::getPlaceComments, placeId)
}
suspend fun deletePlaceComment(placeId: String): Unit? {
return callSafely(client::deletePlaceComment, placeId)
}
suspend fun addPlaceComment(placeId: String, text: String): Unit? {
return callSafely(client::addPlaceComment, placeId, text) // HERE LIES THE PROBLEM
// I can't pass additional data because the method signature won't match with what's defined in callSafely()
}
}
现在,它运行良好,当然我也有Activity和它的ViewModel,并且ViewModel在存储库中调用了一个方法,等等。
重要的是,添加位置注释需要其他数据,例如注释的实际文本。获取和删除注释仅需要placeId,而添加注释时,其内容也需要text
。
我读过在Kotlin中无法传递vararg
函数。我也不想用List of params
之类的东西弄乱所有API方法,在大多数情况下,这些方法将是空的,只会造成混乱。
我可以采用简单的方法,只需将callSafely
的代码复制到addPlaceComment
并进行更改,但这不是我想要的。我知道如何解决问题,但我不知道如何解决the clean way
。将来我可能会添加一些需要更多数据的端点(placeId
除外),问题将再次出现。
在这种情况下您会怎么做?怎么写“正确的方式”?
我什至不知道如何正确表达我要寻找的东西,这就是为什么这篇文章如此繁琐。对不起,提前。我真的希望你能帮助我。
答案 0 :(得分:4)
“干净的方式”是非常广泛的概念。一切都取决于您的需求,没有“做事的一种好方法”。
在您的特定情况下,您有几种选择:
1)类型别名
@array = <STDIN>;
@sorted = sort { $a <=> $b } @array ;
for $i(@sorted)
{
$cnt =0;
for $j(@sorted)
{
if($i eq $j)
{
$cnt = $cnt + 1;
$data{$i}= $cnt;
}
}
}
@modes = sort { $data{$a} <=> $data{$b} } keys %data;
$mode = $modes[-1];
2)Varargs
typealias ApiCall1<P, R> = suspend (P) -> Response<R>
typealias ApiCall2<P1, P2, R> = suspend (P1, P2) -> Response<R>
fun <P> callSafely(param: P, call: ApiCall1<P, YourResult>): YourResult
fun <P1, P2> callSafely(param1: P1, param2: P2, call: ApiCall2<P1, P2, YourResult>): YourResult
3)Lambdas (根据您的情况而定)
没有人强迫您使用方法引用。在需要时使用lambda。但是将lambda放置为“更清洁”代码的最后一个参数。
fun callSafely(vararg params: String, call: suspend (arr: Array<String>) -> YourResult {
...
call(*params)
...
}
答案 1 :(得分:1)
尝试一下:
class SocialRepository {
private val client: Api = ApiClient.webservice
private suspend fun <T> callSafely(
apiMethod: suspend (placeId: String) -> Response<T>,
vararg stringParams: String,
): T? {
Log.d(TAG, "$apiMethod called safely")
var response: Response<T>? = null
try {
response = apiMethod(stringParams[0])
} catch (e: Exception) {
e.printStackTrace()
}
if (response?.isSuccessful != true) {
Log.w(TAG, "response.isSuccessful isn't true.")
}
return response?.body()
}
suspend fun getPlaceComments(placeId: String): List<CommentResponse>? {
return callSafely(apiMethod= client::getPlaceComments, stringParams=*arrayOf(placeId))
}
suspend fun deletePlaceComment(placeId: String): Unit? {
return callSafely(apiMethod=client::deletePlaceComment, stringParams=*arrayOf(placeId))
}
suspend fun addPlaceComment(placeId: String, text: String): Unit? {
return callSafely(apiMethod = client::addPlaceComment,stringParams= *arrayOf(placeId,text))
}
}