Подклассы класса, который реализует универсальный интерфейс - PullRequest
5 голосов
/ 09 марта 2010

Я работаю с Google Web Toolkit, и у меня возникают проблемы с реализацией универсального интерфейса. Я не очень знаком с дженериками, здесь я делаю обновление чужого кода.

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

Интерфейс примерно такой:

public interface AsyncCallback<T> {
    void MethodFromAsyncCallback(T result);
}

Абстрактные и конкретные реализации выглядят примерно так:

class CallbackBase implements AsyncCallback<Object> {
    public abstract void doStuff(Object result);

    public void MethodFromAsyncCallback(Object result) {
        // IMPORTANT STUFF
        // here are things I would like to do for all callbacks, hence the superclass.

        // Then we do the subclass specific things.
        doStuff(result);
    }
}

class SpecificCallback extends CallbackBase
{
    public void doStuff(Object result) {
        Integer i = (Integer)result;
        // do stuff with i
    }
}

Обратные вызовы должны быть запущены с

public interface MyServiceAsync {
    public void DoSomeThing(AsyncCallback<Integer>);
}

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

MyServiceAsync myService = (MyServiceAsync)GWT.create(MyServiceAsync.class);
myService.DoSomeThing(new SpecificCallback());

И вот тут у нас проблема!

Когда GWT.create() реализует созданный мною интерфейс, он требует, чтобы тип, заданный для AsyncCallback, был указан (соответствует типу в другом месте, выходящем за рамки этого вопроса), следовательно, DoSomething(AsyncCallback<Integer>) является целым числом, а не Объект. Это вне моего контроля.

Жалуется, что DoSomething() берет AsyncCallback<Integer>. Я даю ему что-то, что наследуется от чего-то, что AsyncCallback<Object>. Я полагаю, что при использовании дженериков понятия наследования несколько нарушаются?

Итак, мой вопрос:

Либо как мне смешать это вместе, чтобы DoSomething() распознал, что SpecificCallback соответствует его требованиям,

или как я могу структурировать отношения между CallbackBase и SpecificCallback, чтобы избежать дублирования кода, но SpecificCallback реализует AsyncCallback<Integer> напрямую?

Спасибо.

1 Ответ

10 голосов
/ 09 марта 2010

Я думаю, вам нужно определить CallbackBase следующим образом:

abstract class CallbackBase<T> implements AsyncCallback<T> {
  public abstract void doStuff(T result);

  public void MethodFromAsyncCallback(T result) {
    // general stuff (T is a subclass of Object)
    doStuff(result);
  }
}

Тогда вы хотите, чтобы ваши конкретные обратные вызовы были такими:

class SpecificCallback extends CallbackBase<Integer> {
  public void doStuff(Integer result) {
    // no need to cast
    // do stuff with result
  }
}

Тогда ваш метод DoSomething, который принимает AsyncCallback<Integer>, примет SpecificCallback.

(педантичный sidenote: пожалуйста, начинайте все методы со строчных букв в Java)

Редактировать

Для чего бы то ни было, я бы предложил изменить ваш дизайн, чтобы использовать композицию, а не наследование. В этом случае вместо использования абстрактного класса CallbackBase и его расширения вы бы использовали конкретную реализацию AsyncCallback<T>, которая может выглядеть примерно так:

class GeneralCallbackWrapper<T> implements AsyncCallback<T> {
  private final AsyncCallback<? super T> delegate;

  public GeneralCallbackWrapper(AsyncCallback<? super T> delegate) {
    this.delegate = delegate;
  }

  public void MethodFromAsyncCallback(T result) {
    // general stuff here
    delegate.MethodFromAsyncCallback(result);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...