6

我有以下问题:我正在尝试使用 GWT 对流程进行建模,其中我有几个带有几个提交按钮的视图。按下 button1 将创建一个服务器交互,如果一切正常,将加载下一个视图。我现在的问题是我得到了非常讨厌的意大利面条代码(只是非常高级以向您展示我的意思):

onClick {
    AsyncCallback {
       onSuccess {

           load new view with another clickhandler and an asynccallback

       }
    }
}

有什么方法可以创建某种抽象或其他东西吗?也许是状态模式?如何?非常感谢!

4

5 回答 5

6

这实际上是一个非常好的问题——而且可能是一个没有明确答案的问题。这是一个适用于许多框架的问题,而不仅仅是 GWT,所以我喜欢你的想法,用一些简化的代码来看待这个问题。我将把它延长一点,以展示即使只有 4 个非常简单的回调是什么样子的:

嵌套回调

alice.call("a", new Callback() {

  @Override
  public void onSuccess() {
    bob.call("b", new Callback() {

      @Override
      public void onSuccess() {
        charlie.call("c", new Callback() {

          @Override
          public void onSuccess() {
            daisy.call("d", new Callback() {

              @Override
              public void onSuccess() {
                // finished
              }

            });
          }

        });
      }

    });
  }

});

命名回调

您可以使用您的 IDE 轻松地将其重构为命名回调(提示:请从下到上阅读回调!):

final Callback daisyCallback = new Callback() {

  @Override
  public void onSuccess() {
    // finished
  }
};

final Callback charlieCallback = new Callback() {

  @Override
  public void onSuccess() {
    daisy.call("d", daisyCallback);
  }
};

final Callback bobCallback = new Callback() {

  @Override
  public void onSuccess() {
    charlie.call("c", charlieCallback);
  }
};

final Callback aliceCallback = new Callback() {

  @Override
  public void onSuccess() {
    bob.call("b", bobCallback);
  }
};

alice.call("a", aliceCallback);
  • 问题:控制流不再那么明显了。
  • 不过,IDE 可以通过使用“搜索引用”(Eclipse 中的 Ctrl-G)或类似的东西来提供帮助。

事件总线(或观察者/发布-订阅模式)

这是事件总线的相同调用的样子:

alice.call("a", new Callback() {

  @Override
  public void onSuccess() {
    bus.fireEvent(BusEvent.ALICE_SUCCESSFUL_EVENT);
  }
});

bus.addEventListener(BusEvent.ALICE_SUCCESSFUL_EVENT, new BusEventListener() {

  @Override
  public void onEvent(final BusEvent busEvent) {
    bob.call("b", new Callback() {

      @Override
      public void onSuccess() {
        bus.fireEvent(BusEvent.BOB_SUCCESSFUL_EVENT);
      }
    });

  }
});

bus.addEventListener(BusEvent.BOB_SUCCESSFUL_EVENT, new BusEventListener() {

  @Override
  public void onEvent(final BusEvent busEvent) {
    charlie.call("c", new Callback() {

      @Override
      public void onSuccess() {
        bus.fireEvent(BusEvent.CHARLIE_SUCCESSFUL_EVENT);
      }
    });

  }
});

bus.addEventListener(BusEvent.CHARLIE_SUCCESSFUL_EVENT, new BusEventListener() {

  @Override
  public void onEvent(final BusEvent busEvent) {
    daisy.call("d", new Callback() {

      @Override
      public void onSuccess() {
        bus.fireEvent(BusEvent.DAISY_SUCCESSFUL_EVENT);
      }
    });

  }
});

bus.addEventListener(BusEvent.DAISY_SUCCESSFUL_EVENT, new BusEventListener() {

  @Override
  public void onEvent(final BusEvent busEvent) {
    // finished
  }
});
  • 在适当的情况下(当每个事件的含义非常清楚时,并且如果您没有太多事件),这种模式可以使事情变得非常好和清晰。
  • 但在其他情况下,它会使控制流更加混乱(并且您很容易获得两倍的代码行数)。
  • 使用您的 IDE 来查找控制流更加困难。
  • GWT 历史机制是合理使用该技术的一个非常积极的例子。

分而治之

根据我的经验,通过混合嵌套和命名回调来“分而治之”通常是一个好主意:

final Callback charlieCallback = new Callback() {

  @Override
  public void onSuccess() {

    daisy.call("d", new Callback() {

      @Override
      public void onSuccess() {
        // finished
      }
    });
  }
};

alice.call("a", new Callback() {

  @Override
  public void onSuccess() {

    bob.call("b", new Callback() {

      @Override
      public void onSuccess() {

        charlie.call("c", charlieCallback);
      }
    });
  }
});

视情况而定,两个嵌套的回调通常仍然是可读的,并且它们在读取代码时减少了 50% 的方法之间的跳转。

(我在这里创建了我的示例的 pastebin,如果你喜欢玩它们: http: //pastebin.com/yNc9Cqtb

于 2012-07-11T11:09:02.607 回答
1

意大利面条代码在 GWT 中是一个棘手的问题,就像在 Javascript 中一样,您的大部分代码都是围绕异步回调构建的。

该问题的答案中描述的一些处理它的技术可能适用。

于 2012-07-11T09:28:30.993 回答
0

避免小部件之间耦合的建议方法是使用 EventBus。在此处阅读更多详细信息https://developers.google.com/web-toolkit/articles/mvp-architecture#events

希望能帮助到你。

于 2012-07-11T09:13:47.347 回答
0

从一开始就使用 MVP。使用活动和地点。您的代码将是干净的。

于 2012-07-11T09:30:42.163 回答
0
changeview(boolean first){
        if(first)
        {
                firstView.setVisible(true);
                secondView.setVisible(false);
        }else{
                firstView.setVisible(false);
                secondView.setVisible(true);
        }
}

onClick {
    AsyncCallback {
       onSuccess {
                changeView(false);
       }
    }
}

通过上面的视图在视图之间切换。

于 2012-07-11T09:35:12.493 回答