2010-02-05 3 views
1

В моем приложении я выполнения транзакции, которая может находиться в трех различных состояниях в конце исполнения:Использование обратного вызова вместо возврата объекта состояния

  • Успех
  • Failure
  • В ожидании

В зависимости от состояния клиент приложения будет выполнять различные действия. В случае успеха они захотят получить результат транзакции (виджет). В случае сбоя они захотят получить причину ошибки. В случае ожидания транзакции они захотят запланировать время для повторной попытки. В настоящее время я возвращаю объект со следующими методами:

public interface Result() { 
    State getState(); 
    Widget getWidget(); // Success 
    Reason getFailureReason(); // Failure 
    Callable<Result> getTask(); // Pending 
} 

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

if (result.getState() == State.PENDING) { 
    result.getTask(); 
} 

Я думал, что предпочтительнее использовать обратный вызов, например,

public interface TransactionCallback() { 
    void onFailure(Reason reason); 
    void onSuccess(Widget widget); 
    Delay onPending(Delay previous); 
} 

Где Delay это класс, представляющий TimeUnit и период, что позволяет приложению перенести выполнение транзакции. Другой альтернативой является бросить исключение, обертывающее причину сбоя (поскольку оно должно только терпеть неудачу в исключительных условиях), и сохраняйте методы onSuccess10 и onPending.

Итак, мой вопрос к SO: это использование обратного вызова соответствующего шаблона для этой конкретной проблемы, или кто-нибудь может предложить что-то более подходящее?

ответ

2

Я не думаю, что это хороший подход к обратному шаблону.

Обратный вызов подходит, если вызов (например, транзакция в вашем случае) должен продолжать выполнять действия после возврата метода обратного вызова. Но если следующая вещь, которую всегда вызывает вызываемый, - это возврат к вызывающему, тогда обратный вызов не добавляет никакого значения. Это просто делает структуру кода более сложной и менее читаемой.ИМО, было бы лучше вернуть объект результата или (в случае исключительного отказа) вызвать исключение.

EDIT - комментарий Комитета.

Я могу увидеть значение метода обратного вызова, чтобы спросить вызывающего, если транзакция должна продолжаться, хотя я, вероятно, использовал бы простой параметр таймаута. Однако использование методов обратного вызова для возврата результатов (IMO) по-прежнему не так.

+0

Но это не всегда так: если транзакция находится в состоянии ожидания *, транзакция будет продолжать опрос до тех пор, пока транзакция не завершится успешно или не сработает. Возврат из метода onPending() требуется, чтобы узнать, как долго ждать следующего опроса. –

+0

Мне нравится идея полностью отменить ожидающую ситуацию с таймаутом (хотя, вероятно, время между запросами не обязательно будет равным), но я не уверен, что вы не согласны использовать обратный вызов. Есть ли у вас какие-либо ссылки, подтверждающие ваше мнение? –

+0

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

3

Я предпочитаю обратные вызовы, так как если вы используете его в нескольких местах, это приведет к уменьшению количества кода и станет более читаемым. С вызовом вашего оператора if, чтобы определить, что произойдет (какой метод для вызова) будет находиться в сервисе, выполняющем транзакцию, и весь код, использующий эту услугу, будет выглядеть только чище.

+0

Это были мои рассуждения. –

+0

Согласен. Я нахожу более недействительные методы и обратные вызовы, которые я использую, чем чище мой код, тем лучше. Разделение запроса, обработка результата и обработка ошибок на отдельные методы (если не отдельные объекты), по-видимому, приводят к более чистым, более удобным для обслуживания коду. – kyoryu

2

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

Конечно, при опросе результата вам потребуется синхронизация с другой стороны. Но это звучит проще для синхронизации.

+0

Обратный вызов не является асинхронным, поэтому я не уверен, что ваши проблемы действительны * в этом случае *. –

+0

Но он может быть асинхронным, если вы запускаете рабочую нагрузку в отдельном потоке. Одна хорошая вещь о методах void и обратных вызовах заключается в том, что вы можете отправить произведение в отдельный поток в любой момент. Во всяком случае, даже с синхронным возвратом, вы не можете быть уверены в состоянии своего объекта, когда получите возвращаемое значение, если вы не заблокируете объект в любом случае. Я бы сказал, что это приводит к лучшему дизайну в любом случае. – kyoryu

+0

@ Давид Ок. Однако объект может быть включен как аргумент для интерфейса, тем не менее, или вам нужно будет настроить какое-то состояние в объекте получателя, чтобы он знал, откуда взялись результаты. При необходимости следует избегать добавления большего количества состояний. – ron

0

Решение обратного вызова много расширяемо, хотя вы можете в какой-то момент изменить поведение на асинхронный вызов.

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

Смежные вопросы