Обратный вызов / Команда против шаблона EventListener / Observer - PullRequest
29 голосов
/ 21 января 2012

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

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, который имеет свою семантику по приоритету слушателей и как обрабатывать распределение событий для каждого слушателя, например, порождая новый поток для каждого слушателя против последовательных уведомлений. (Я на самом деле думаю, что это хорошая идея, так как это хорошее разделение интересов и улучшение стандартного паттерна наблюдатель / слушатель).

Есть мысли о том, когда вы должны использовать каждый?

Thxs.

Ответы [ 4 ]

30 голосов
/ 22 января 2012

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

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

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

  1. Используйте шаблон callback для запуска операций и асинхронного уведомления вызывающей стороны о том, что запущенная операция завершена.
  2. Используйте шаблон событие / наблюдатель , чтобы дать некоторым другим компонентам (которые не инициировали операцию) возможность получать уведомления о завершении операции.
23 голосов
/ 21 января 2012

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

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

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

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

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

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

или

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

тогда вы должны пойти с простым 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 из библиотеки гуавы.

5 голосов
/ 21 января 2012

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

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

0 голосов
/ 08 апреля 2018

Оба шаблона имеют несколько общих намерений, за исключением

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

В шаблоне команд легко реализовать операцию отмены.

Приветствия!

...