【问题标题】:Using a callback instead of returning state object使用回调而不是返回状态对象
【发布时间】:2011-01-13 10:33:19
【问题描述】:

在我的应用程序中,我正在执行一个在执行结束时可能处于三种不同状态的事务:

  • 成功
  • 失败
  • 待处理

根据状态,应用程序客户端将希望执行不同的操作。在成功的情况下,他们会想要检索交易结果(一个Widget)。在失败的情况下,他们将希望收到错误原因。在事务未决的情况下,他们将希望安排时间重试。目前我使用以下方法返回一个对象:

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 和句点的类,允许应用程序重新安排事务执行。另一种选择是抛出一个包含失败原因的异常(因为它应该只在异常情况下失败),并保留onSuccess 和onPending 方法。

所以我对 SO 的问题是:对于这个特定问题,使用回调是一种合适的模式吗,或者任何人都可以提出更合适的建议吗?

【问题讨论】:

    标签: java callback design-patterns listener


    【解决方案1】:

    我认为这不是回调模式的好用处。

    如果被调用者(例如您的事务)需要在回调方法返回后继续执行操作,则回调是合适的。但是如果被调用者总是做的下一件事是返回给调用者,那么回调不会添加任何值。它只是使代码结构更复杂,可读性更差。 IMO,最好返回结果对象或(在异常失败的情况下)抛出异常。

    EDIT - 回复 OP 的评论。

    我可以看到使用回调方法询问调用者事务是否应该继续的价值,尽管我可能会使用一个简单的超时参数。但是,使用回调方法返回结果(IMO)仍然是错误的。

    【讨论】:

    • 但情况并非总是如此:如果事务处于 pending 状态,事务将一直轮询直到事务成功或失败。 onPending() 方法的返回需要知道等待下一次轮询的时间。
    • 我喜欢用超时完全消除待处理情况的想法(尽管请求之间的时间可能不一定相等),但我不是完全因您不愿使用回调而深信不疑。你有任何参考资料来支持你的观点吗?
    • 我同意斯蒂芬的观点。在这种情况下,回调只会使代码更难遵循。我理解使代码可扩展的愿望,但是通过牺牲可读性,你牺牲了可维护性。我认为有朝一日,其他程序员更可能不会理解代码并比您利用回调添加的可扩展性弄得一团糟。
    • @David - 我的参考是常识。只需比较两种实现方式的代码量/复杂性,您就会发现差异。
    【解决方案2】:

    回调解决方案具有很大的可扩展性,而您有时可能希望将行为更改为异步调用。

    缺点是您的代码可读性较差,尤其是对于那些初学者程序员。如果这对你来说不是问题,那么确定,继续...

    【讨论】:

      【解决方案3】:

      回调参数应包括调用调用的对象。对我来说听起来不错,但使用回调可能会涉及一些同步问题——你不能确定你会在哪个状态下收到回调。并非不可能,但可能需要考虑。

      当然,在轮询结果时,您需要在另一端进行同步。但这听起来更容易同步。

      【讨论】:

      • 回调不是异步的,所以我不确定您的担忧是否有效在这种情况下。
      • 但如果您在单独的线程中运行工作负载,它可能是异步的。 void 方法和回调的一个好处是您可以随时将工作分派到单独的线程。无论如何,即使使用同步返回,当您获得返回值时,您也无法确定对象的状态,除非您无论如何锁定该对象。我想说它在任何一种情况下都会带来更好的设计。
      • @David 好的。但是,该对象可能仍然作为接口的参数包含在内,或者您必须在接收器对象中设置一些状态,以便它知道结果来自哪里。如果可能,应避免添加更多状态。
      • 最终用户将看不到交易,所以我不确定传回该对象是否会对最终用户有很大帮助。我也一直在考虑最终用户可以用来识别特定操作的手回对象的用户。
      • @kyoryu:也许是时候让我回到实践中的并发了。 ;)
      【解决方案4】:

      我更喜欢回调,因为如果你在多个地方使用它,它会减少代码并提高可读性。通过回调您的 if 语句来确定将发生什么(调用哪个方法)将在执行事务的服务中,并且使用该服务的所有代码看起来都更清晰。

      【讨论】:

      • 同意。我发现我使用的 void 方法和回调越多,我的代码最终就会越干净。将发出请求、处理结果和处理错误分成单独的方法(如果不是单独的对象)似乎会产生更清晰、更易于维护的代码。
      猜你喜欢
      • 2019-12-29
      • 2021-12-18
      • 2021-01-25
      • 2019-03-23
      • 2012-09-28
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 2013-12-29
      相关资源
      最近更新 更多