【问题标题】:Anonymous Inner Classes: When are they (in)appropriate?匿名内部类:它们何时(不)合适?
【发布时间】:2011-12-12 14:03:28
【问题描述】:

举个例子。我想使用一个对象,称之为DoodadDoodad 元素对浏览器事件的处理效果不佳。 Doodad 的典型实例化为 Doodad someDoodad = new Doodad();。显然这不适合我的需要,因为糟糕的事件处理。我是否适合重写onBrowserEvent() 方法,如下所示:

Doodad someDoodad = new Doodad() {
@Override
  public void onBrowserEvent(Event event) {
      switch (DOM.eventGetType(event)) {
          case Event.ONDBLCLICK:
          case Event.ONFOCUS:
          case Event.ONCLICK:
              if (!isEnabled()) {
                  return;
              }
              break;
      }
      super.onBrowserEvent(event);
  }
};

显然这是一个简单的例子,但我什么时候想使用匿名内部类?是否曾明确禁止或不可能?

我看到很多关于第一个问题的答案,但到目前为止没有一个答案能回答第二个问题:是否曾明确禁止或不可能使用匿名内部类?

【问题讨论】:

  • 和上面的例子一样,我主要是在事件处理案例中看到的。

标签: java overriding anonymous-class anonymous-inner-class


【解决方案1】:

通常情况下,匿名内部类的最佳用法是当您只想创建此类特定实现的一个实例时。当实现非常简单时。理想情况下,它应该包含 1-2 行代码。

在您的情况下,尽管您的方法 onBrowserEvent() 超过 2 行,但它仍然可以。

【讨论】:

  • 公平地说,OP 不遗余力地将 2 行变为 6 行,使用 switch 语句而不是 if 语句。
  • @glowcoder 有 6 行可以理解:什么时候合适使用匿名内部类。我本可以在两行中完成同样的事情,但希望看到与代码长度(实际用法)以及功能用法相关的答案。
  • 我更喜欢给枚举添加方法。在这种情况下,我将定义方法proceedBrowserEvent 并为枚举的每个成员实现它。在这种情况下,监听器应该真正调用一个方法,所以它只有一行。
【解决方案2】:

匿名内部类是 Java 创建闭包的语法。这是一个大概的例子:

interface Adder {
  int add(int arg);
}

...

Adder createAdder(int n) {
   final int nf = n;
   return new Adder() { 
       int add(int arg) { return arg + nf; } 
   }
}

方法 createAdder 创建本质上是一个函数,它使用闭包来捕获传递的值 n。闭包在试图使其成为主流的函数式编程中很重要。这就是为什么每个人都在尖叫我们在 Java 中需要“真正的”闭包(即大多数语法比我的示例中更好)。

(当然我没有回答所提出的问题;我想我的意思是匿名类对我上面描述的内容有好处。对于几乎所有其他的东西,我都会创建一个命名的内部类,因为如果有任何名字是自我记录,在我看来更容易阅读)

【讨论】:

  • 是的,您需要手动捕获它们的事实很糟糕,但这只是句法,而不是功能缺陷。
【解决方案3】:

通常,事件侦听器是一段不是很通用的代码,但与特定的小部件、按钮、文本字段等相关联。在这种情况下,代码不需要适当地公开以供世界重用。在使用它的地方、就地定义它更容易,这就是匿名内部类的用途。它们允许将代码片段快速嵌入到另一个方法中,而不必担心类名、包、可见性或可重用性。

当然,你可以用匿名内部类做的事情总是可以用适当的独立类来做。但是,当您的事件处理类足够通用(可以处理大量事件)、可重用、有状态或更一般地,当从代码中提取事件管理代码有一些好处时,这样做更有意义定义事件生成元素。

我不确定我是否具体理解了您的问题,希望这条信息可以帮助您找到答案。不要犹豫,问更多问题。

【讨论】:

    【解决方案4】:

    当它实现一种方法和/或半屏时,我会建议匿名类。

    如果匿名者有一段不平凡的代码,那么它值得拥有一个命名类恕我直言。

    【讨论】:

    • poor event handling 是什么意思?
    • 在 OP 中,我提到“Doodads 的事件处理能力很差”。假设当它是disabled 时,它不正确地处理点击。
    • 类是命名的还是匿名的对其行为没有影响(除了默认的toString),如果它有poor event handling,如果它被命名它仍然会有这个。
    【解决方案5】:

    我的看法:

    匿名内部类:来自一个函数的回调(因此您无需编写两次代码)

    命名内部类:来自多个函数的回调(或仅用于父类的内部逻辑的类)

    【讨论】:

      【解决方案6】:

      我只在匿名内部类包含非常少量的代码时才使用它。原因是 IMO 会混淆代码并降低其可读性。

      如果需要更多代码,我更喜欢创建一个新类,扩展基类(在本例中为“Doodad()”

      【讨论】:

      • 你的例子对我来说没问题,但除此之外,我更倾向于创建一个单独的类。
      【解决方案7】:

      在您的示例中,您希望创建一个单独的类。这是因为您覆盖该方法的原因。也就是说,对浏览器事件的处理很差。

      具体来说,您可能希望在几个不同的地方创建这些改进的 Doodad。如果将来更新和改进事件处理会发生什么?您将希望删除所有这些改进的 Doodads 并使用正确的实现。试图找到你所有的匿名小玩意可能会让人厌烦或棘手。而如果你有一个单独的命名类,那么重构这个类会很容易。

      此外,如果您为 Doodad 创建一个单独的类,那么您改进 Doodad 的原因可以是自我记录。而如果你只有一个匿名类,那么你将不得不编写 cmets 或让未来的维护者猜测你为什么做了你所做的事情。

      例如。

      public class ImprovedBrowserEventHandlingDoodad extends Doodad {
          ...
      }
      

      任何类似于闭包的东西通常都适合使用匿名类

      例如。

      new Thread(new Runnable() {
          @Override
          public void run() {
              doSomething();
          }
      }).start();
      

      您只想在这一组特定的情况下做某事,而无需将代码复制并粘贴到其他地方或将其重构为方法。

      GUI 的事件处理程序通常使用匿名类,因为它们的使用仅限于 GUI 的设计方式,并且无需在使用它的特定组件之外创建事件处理程序的单独实例。例如,当您将鼠标悬停在滚动条上时,它的外观通常会发生变化。程序中的任何其他内容都不会导致此更改,通常事件处理程序将是几行告诉滚动条更改其外观,例如。 scrollbar.setMouseOverEffect(true);.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多