Использование модифицированной методики более выразительный способ


Я хочу сделать void enqueue(Callback<T> callback); метод вызова блока кода более выразительным, вот что у меня обычно

request.enqueue(object : Callback<MyModel> {
      override fun onFailure(call: Call<MyModel>?, t: Throwable?) {
           //
      }

      override fun onResponse(call: Call<MyModel>?, response: Response<MyModel>?) {
           //
      }
 })

И что хотят и имеют в виду, чтобы изменить этот код блоков более чистым способом и удалить эти переопределение, объект, обратный вызов ключевые слова и сделать что-то вроде этого:

request.enqueue({throwable, response -> })

Я думаю, что его можно как-то улучшить, используя расширения и функции более высокого порядка. Кто-нибудь знает, как это можно сделать?

3 12

3 ответа:

Дана следующая функция:

fun <T> callback(fn: (Throwable?, Response<T>?) -> Unit): Callback<T> {
    return object : Callback<T> {
        override fun onResponse(call: Call<T>, response: retrofit2.Response<T>) = fn(null, response)
        override fun onFailure(call: Call<T>, t: Throwable) = fn(t, null)
    }
}

Вы можете использовать это при модернизации следующим образом:

request.enqueue(callback({ throwable, response ->
 response?.let { callBack.onResponse(response.body() ?: RegisterResponse()) }
 throwable?.let { callBack.onFailed(throwable.message!!) })

Альтернативно, вы можете определить эту другую версию обратного вызова:

fun <T> callback2(success: ((Response<T>) -> Unit)?, failure: ((t: Throwable) -> Unit)? = null): Callback<T> {
    return object : Callback<T> {
        override fun onResponse(call: Call<T>, response: retrofit2.Response<T>) { success?.invoke(response) }
        override fun onFailure(call: Call<T>, t: Throwable) { failure?.invoke(t) }
    }
}


который может быть использован следующим образом:

request.enqueue(callback2(
                { r -> callBack.onResponse(r.body()) },
                { t -> callBack.onFailed(t.message) }))

Вот что вы можете сделать (это Java, так как я не знаю много Kotlin, но это должно быть очень похоже):

public class CallbackWrapper<T> implements Callback<T> {
    private Wrapper<T> wrapper;

    public CallbackWrapper(Wrapper<T> wrapper) {
        this.wrapper = wrapper;
    }

    public void onFailure(Call<T> call, Throwable t) {
        wrapper.onResult(t, null);
    }

    public void onResponse(Call<T> call, Response<T> response) {
        wrapper.onResult(null, response);
    }

    public static interface Wrapper<T> {
        void onResult(Throwable t, Response<T> response);
    }
}

Который вы можете использовать как:

call.enqueue(new CallbackWrapper((throwable, reponse) - > {...}));

Обновление решения для kotlin:

На основе этого , CallBackWrapper выглядит следующим образом:

typealias wrapper<T> = (t: Throwable?, response: Response<T>?) -> Unit

class CallbackWrapper<T>(val wrapper: wrapper<T>) : Callback<T> {
   override fun onFailure(call: Call<T>?, t: Throwable?) = wrapper.invoke(t,null)
   override fun onResponse(call: Call<T>?, response: Response<T>?) = wrapper.invoke(null, response)
}

И использовать его так же, как Java.

Я использовал функцию расширения на Call, чтобы написать выразительный и общий метод enqueue.

fun<T> Call<T>.onEnqueue(actOnSuccess: (Response<T>) -> Unit, actOnFailure: (t: Throwable?) -> Unit)   {
    this.enqueue(object: Callback<T>    {
        override fun onFailure(call: Call<T>?, t: Throwable?) {
            actOnFailure(t)
        }

        override fun onResponse(call: Call<T>?, response: Response<T>) {
            actOnSuccess(response)
        }
    })
}

Это может быть использовано как:

request.onEnqueue    {
    actOnSuccess = {
        doOnSuccess()
    }
    actOnFailure = {
        doOnFailure()
    }
}

В блоках кода actOnSuccess и actOnFailure, it должны относиться к объектам Response и Throwable соответственно, и могут быть использованы соответственно. Например, в блоке кода actOnFailure -

actOnFailure = {
        doOnFailure()
        //it.message //'it' refers to the Throwable object.
    }