匿名类覆盖vs传递接口,用于设计Java中的回调

时间:2012-11-02 22:37:49

标签: java interface callback anonymous

我知道在Java中使用3种不同的回调类型功能,但我并不完全了解每种方法的优缺点。

Java API丰富了与此类似的方法:

Button b = new Button();
b.setClickListener(<implements ClickListener>);

我使用“按钮”作为通用示例,而不是引用任何特定的API。

1。)使用它的一种方法是让你的类实现接口并将其作为参数传递。要处理多个“按钮”,您必须使用调用者为回调提供的任何信息来区分。

MyClass implements ClickListener
...
Button b = new Button();
b.setClickListener(this);
...
public void click(ButtonEvent e)
{
...

2。)另一种方法是在现场制作一个匿名的ClickListener,让它的“click”方法包含你想要执行的代码。这有一些额外的好处,因为您可以使用本地最终变量向回调添加新参数。

for(int i=0 ; i<10 ; i++)
{
  final int finali = i;
  buttons[i] = new Button();
  buttons[i].setClickListener(new ClickListener()
  {
    public void click()
    {
      buttonClick(finali);
    }
  });
}

3。)如果您正在编写调用回调的类,那么最后一种方法是可行的。您可以匿名覆盖要捕获的回调方法。最明显的缺点是无法在对象的生命周期内切换回调。

for(int i=0 ; i<10 ; i++)
{
  final int finali = i;
  buttons[i] = new Button()
  {
    public void click()
    {
      buttonClick(finali);
    }
  }
}

选项3在许多方面似乎是最“简单”的。它不需要进行各种接口,回调函数总是初始化的地方。

所以我的问题是:在考虑这些设计选择时会有哪些因素发挥作用?

2 个答案:

答案 0 :(得分:2)

选项1通常很方便,但如果你想要监听多个对象就会出现问题,因为你必须明确检查哪一个触发了回调。

选项2避免了这个问题,因为每个监听器是分开的;它是三种方法中最灵活的。

选项3是一个坏主意,因为你基本上是接管Button而不是监听事件(即这根本不是回调);您可能会干扰对该按钮感兴趣的其他代码,并且代码将更难扩展。不要跟随黑暗面;-)。

通常你不会写一个调用回调的类......

答案 1 :(得分:2)

前两个是同一个。唯一的区别是谁实现了监听器接口。它使用了可观察/观察者设计模式。

最后一个使用继承,而且不太灵活:

  • 您只能设置构建按钮时必须完成的操作
  • 之后你无法改变这种行为
  • 您只能注册一次点击操作
  • 您无法通过点击删除操作
  • 您需要让您的课程成为非最终版本,并且点击方法可以覆盖
  • 您无法将相同的侦听器添加到多个按钮,从而导致代码重复
  • ...

第一个肯定是更好的选择(并且是Swing,Android,JavaScript事件等使用的解决方案)。一般来说,组成应该优于继承。这个案例就是这个规则的完美例子。