2017-01-18 2 views
4

Я сделал это упрощенный пример моего реального кода, не компиляции:Java генериков с подстановочные не компиляции

public class Example { 

    public static void main(String[] args) { 
     Callback<BalanceResponse> balanceRequestCaller = new Callback<BalanceResponse>() { 
      @Override 
      public void onResponse(BalanceResponse response) {} 

      @Override 
      public void onFailure(String error, int code) {} 

      @Override 
      public void onFailure(Throwable t) {} 
     }; 

     BalanceRequest breq = new BalanceRequest(); 

     Interceptor interceptor = new Interceptor(balanceRequestCaller); 

     breq.startRequest((Callback<BaseResponse>) interceptor); //compile-time error!!! 
    } 


    public static class Interceptor implements Callback<BaseResponse> { 

     public Interceptor(Callback<? extends BaseResponse> originalCaller) { 
      this.originalCaller = originalCaller; 
     } 

     private Callback<? extends BaseResponse> originalCaller; 

     @Override 
     public void onResponse(BaseResponse response) { 
      //do some interception stuff 

      if (response instanceof BalanceResponse) { 
       ((Callback<BalanceResponse>) originalCaller).onResponse((BalanceResponse) response); 
      } else if (response instanceof SubscriptionResponse) { 
       ((Callback<SubscriptionResponse>) originalCaller).onResponse((SubscriptionResponse) response); 
      } 
     } 

     @Override 
     public void onFailure(String error, int code) {} 

     @Override 
     public void onFailure(Throwable t) {} 
    } 

    public interface Request<T extends BaseResponse> { 
     void startRequest(Callback<T> callback); 
    } 

    public static class BalanceRequest implements Request<BalanceResponse> { 
     @Override 
     public void startRequest(Callback<BalanceResponse> callback) {} 
    } 

    public static class SubscriptionRequest implements Request<SubscriptionResponse> { 
     @Override 
     public void startRequest(Callback<SubscriptionResponse> callback) {} 
    } 

    public static class BaseResponse { 
     public String status; 
    } 

    public static class BalanceResponse extends BaseResponse { 

    } 

    public static class SubscriptionResponse extends BaseResponse { 

    } 

    public interface Callback<T> { 
     void onResponse(T response); 
     void onFailure(String error, int code); 
     void onFailure(Throwable t); 
    } 
} 

То, что я пытаюсь сделать, это сделать Interceptor, что бы перехватить обратный вызов, сделать некоторые вещи с ответом, а затем передать его первоначальному обратному вызову.

Я хочу создать общий Interceptor, который мог бы перехватить любой обратный вызов, который равен Callback<? extends BaseResponse>.

Кстати ошибка во время компиляции я получаю от NetBeans является

incompatible types: Callback<BaseResponse> cannot be converted to Callback<BalanceResponse> 

Дайте мне предложения, как я мог бы сделать эту работу?

ответ

3

Вы должны определить параметр в типа на классе Interceptor, чтобы предотвратить вашу ошибку компиляции и избежать явных приведений в методе onResponse, который, как правило, является доказательством проблемы дизайна.

Ваш класс перехватчик с параметром в типа:

public static class Interceptor<T extends BaseResponse> implements Callback<T> { 

    public Interceptor(Callback<T> originalCaller) { 
     this.originalCaller = originalCaller; 
    } 

    private Callback<T> originalCaller; 

    @Override 
    public void onResponse(T response) { 
     originalCaller.onResponse(response); 
    } 

    ... 
} 

Вы бы затем создать его экземпляр и использовать его в следующем:

Interceptor<BalanceResponse> interceptor = new Interceptor<>(balanceRequestCaller); 
breq.startRequest(interceptor); 
1

Изменить подпись startRequest() подписи

void startRequest(Callback<? super T> callback); 

Этот алло ws, чтобы принять более общий обратный вызов, вместо того, чтобы требовать только самый узкий тип. Для получения дополнительной информации см. What is PECS (Producer Extends Consumer Super)?

EDIT: @teppic's answer - лучшее решение, если вы не должны повторно использовать один экземпляр Interceptor для разных типов запросов. Если это так, вы все равно можете свести шаблон к одной делегации:

@Override 
public void onResponse(BaseResponse response) { 
    //do some interception stuff 
    ((Callback<BaseResponse>)originalCaller).onResponse(response); 
} 
Смежные вопросы