Подтвердить что ты не робот

Обратный вызов/команда против шаблона EventListener/Observer

Я пытаюсь создать асинхронную структуру и хотел бы знать, что люди думают, являются плюсами/минусами шаблона обратного вызова против шаблона наблюдателя.

Callback pattern:

//example callback
public interface Callback{
    public void notify(MethodResult result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback callback){
     //do work
     callback.notify(result);
  }
}

//example observer pattern
public interface EventListener{
   public void notify(MethodResult result);

}

public class Worker{
  private EventListener listener;
  public registerEventListener(EventListener listener){
   this.listener=listener;
  }
  public void doAsyncWork(){
     //do work
     listener.notify(result);
  }
}

Я работаю с фреймворком, который, как представляется, использует оба этих шаблона. Шаблон EventListener не является типичным шаблоном, так как у него нет списка слушателей. Это можно легко реализовать, создав CompositeListener, который имеет свою собственную семантику по приоритету слушателей и как обрабатывать распределение событий для каждого слушателя, например. создавая новый поток для каждого прослушивателя и серийных уведомлений. (Я на самом деле думаю, что это хорошая идея, так как это хорошее разделение проблем и улучшение стандартного шаблона наблюдателя/слушателя).

Любые мысли о том, когда вы должны использовать их?

спасибоs.

4b9b3361

Ответ 1

Оба шаблона великолепны, и каждый из них зависит от того, что вы собираетесь создавать и как будет использоваться ваша фреймворк.

Если вы пытаетесь создать какую-то систему публикации-подписки со следующим типичным потоком работы:

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

тогда Observer шаблон является естественным выбором для вас. Поскольку вы делаете фреймворк, вы также должны рассмотреть возможность использования EventBus для достижения свободной связи.

Если вам нужно не что иное, как простое асинхронное выполнение и типичный поток, использующий вашу инфраструктуру:

  • Запустить задачу async
  • сделать что-нибудь, когда оно будет завершено

или

  • Запустить задачу async
  • сделать что-то
  • дождитесь завершения и сделайте что-нибудь.

тогда вы должны пойти с простым Callback.

Но для того, чтобы достичь более удобного и чистого API, я бы рекомендовал вам избавиться от абстракции Callback и разработать свой рабочий код, чтобы вернуть какой-то Future.

public interface Worker<T> {

    Future<T> doAsync();

}

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

Future<Integer> future = worker.doAsync();

// some work here

Integer result = future.get(); // waits till async work is done

Future может быть стандартным java Future. Но я предлагаю вам использовать ListenableFuture из библиотеки guava.

Ответ 2

Шаблоны команд, обратного вызова и наблюдателя имеют разную семантику:

  • callback - уведомляет одного вызывающего абонента о завершении некоторой операции с некоторым результатом
  • observer - уведомляет нулевые заинтересованные стороны о том, что произошло какое-то событие (например, законченная операция)
  • команда - инкапсулирует вызов операции в объекте, тем самым делая его переносимым по проводу или сохраняющемуся

В вашем примере вы можете комбинировать обратные вызовы и шаблоны наблюдателей для достижения большей гибкости API:

  • Используйте шаблон callback для запуска операций и асинхронно уведомлять вызывающего абонента о завершении запуска.
  • Используйте шаблон event/observer, чтобы предоставить некоторые другие компоненты (которые не запускали операцию), чтобы получить уведомление о завершении операции.

Ответ 3

Я бы сказал, что шаблон обратного вызова лучше, поскольку он проще, что означает, что он будет более предсказуемым и с меньшей вероятностью иметь ошибки из-за его собственного мутирующего состояния. Примером этого может быть способ, которым GWT обрабатывает связь между браузером и сервером.

Возможно, вы захотите использовать дженерики:

//example callback
public interface Callback<T> {
    public void notify(T result);
}

//example method
public class Worker{
  public void doAsyncWork(Callback<SomeTypeOrOther> callback){
     //do work
     callback.notify(result);
  }
}