Обратный вызов / команда vs EventListener / шаблон наблюдателя
Я пытаюсь создать асинхронную структуру и хотел бы знать, что люди думают о плюсах и минусах шаблона обратного вызова против шаблона наблюдателя.
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 ответов
оба шаблона велики, и какой из них выбрать, зависит от того, что вы собираетесь строить и как будет использоваться ваша структура.
если вы пытаетесь построить какую-то систему публикации-подписки со следующим типичным потоком работы:
- клиент запускает асинхронную задачу и забывает об этом
- несколько обработчиков получает уведомления, когда задача выполнена
затем Observer
массив-это естественный выбор для вас. Как и ты делаете фреймворк, который вы также должны рассмотреть с помощью EventBus картина для того чтобы достигнуть свободного соединения.
Если вам не нужно ничего больше, чем простое асинхронное выполнение и типичное использование потока вашей структуры:
- пуск асинхронных задач
- сделайте что-нибудь, когда он будет завершен
или
- пуск асинхронных задач
- сделать что-то
- подождите, пока он не будет завершен и сделать что-то!--15-->
тогда вы должны пойти с простым 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. Но я бы посоветовал вам использовать ListenableFuture
из гуавы библиотека.
Шаблоны команд, обратного вызова и наблюдателя имеют различную семантику:
- обратный звонок - уведомляет одного вызывающего абонента, что некоторая операция закончилась с некоторым результатом
- обозреватель - уведомляет ноль заинтересованных лиц о том, что произошло какое-то событие (например, завершенная операция)
- команда - инкапсулирует вызов операции в объекте, что делает его переносимым по проводу или упорствовать-способен
в вашем примере вы можете объединить шаблоны обратного вызова и наблюдателя для достижения большей гибкости API:
- использовать обратный звонок шаблон для запуска операций и асинхронного уведомления вызывающего абонента о завершении инициированной операции.
- использовать событие/обозреватель pattern, чтобы дать некоторые другие компоненты (что сделал не триггер операции) возможность получать уведомления, когда операция завершена.
Я бы сказал, что шаблон обратного вызова лучше, поскольку он проще, что означает, что он будет более предсказуемым и с меньшей вероятностью будет иметь ошибки из-за собственного мутирующего состояния. Примером этого в работе будет способ 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);
}
}
оба шаблона имеют мало общих намерений, за исключением,
наблюдаемый шаблон может уведомлять несколько слушателей. С другой стороны, шаблон команды будет лучше всего подходит, где вам нужен один обработчик обратного вызова.
в шаблоне команды легко реализовать операцию отмены.
Ура!