这实际上是一个非常好的问题——而且可能是一个没有明确答案的问题。这是一个适用于许多框架的问题,而不仅仅是 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)