Вложенный класс vs реализует ActionListener

Есть ли какие-либо преимущества или недостатки для создания вложенного класса, который реализует ActionListener:

public class Foo{
    Foo(){
        something.addActionListener(new ButtonListener());
    }
    //...
    private class ButtonListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            //...
        }
    }
}

против реализации ActionListener в самом основном классе:

public class Foo implements ActionListener{
    Foo(){
        something.addActionListener(this);
    }
    //...
    public void actionPerformed(ActionEvent e){
        //...
    }
}

Я видел оба примера довольно часто и просто хочу знать, есть ли "лучшая практика".

Ответ 1

@Ankur, вы все равно можете использовать анонимные внутренние классы в качестве ваших слушателей и иметь отдельный отдельно стоящий класс управления и, следовательно, иметь код, который вполне поддерживается, метод, который мне нравится использовать. Например:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AnonymousInnerEg {
   private static void createAndShowUI() {
      GuiPanel guiPanel = new GuiPanel();
      GuiControl guiControl = new GuiControl();
      guiPanel.setGuiControl(guiControl);

      JFrame frame = new JFrame("AnonymousInnerEg");
      frame.getContentPane().add(guiPanel);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

class GuiPanel extends JPanel {
   private GuiControl control;

   public GuiPanel() {
      JButton startButton = new JButton("Start");
      startButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            if (control != null) {
               control.startButtonActionPerformed(e);
            }
         }
      });
      JButton endButton = new JButton("End");
      endButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            if (control != null) {
               control.endButtonActionPerformed(e);
            }
         }
      });

      add(startButton);
      add(endButton);
   }

   public void setGuiControl(GuiControl control) {
      this.control = control;
   }


}

class GuiControl {
   public void startButtonActionPerformed(ActionEvent ae) {
      System.out.println("start button pushed");
   }

   public void endButtonActionPerformed(ActionEvent ae) {
      System.out.println("end button pushed");
   }
}

Ответ 2

Я думаю, что первый подход лучше, так как ваш класс будет иметь отдельный код для обработки действий. И обычно также состав лучше, чем наследование, поэтому класс должен расширять класс или реализовывать интерфейс только в том случае, если он действительно является супер-типом.

Кроме того, для удобства обслуживания, скажем, класс Foo имеет новое требование прослушивания другого типа событий, а затем выполнить действие, и в этом случае также можно легко изменить первый класс.

Если меня не беспокоит ремонтопригодность, я бы предпочел пойти на анонимный класс.

Ответ 3

Если класс Foo не несет никакой другой ответственности, чем инкапсуляция этой кнопки, то первое решение будет вроде ok.

Однако, как только Foo получает больше "somethings", что он должен слушать, тогда он становится беспорядочным. Я предпочитаю второе решение, поскольку оно более явное и имеет лучшую масштабируемость.

Еще лучшим решением может быть создание аномального внутреннего класса.

public class Foo{
    Foo(){
        something.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e){
                //...
            }
        });
    }
}

Ответ 4

Обычно вы хотите использовать вложенный или даже анонимный класс, а не подвергать ActionListener API входящего класса. (public class Foo реализует ActionListener → Javadoc укажет, что Foo является ActionListener, хотя обычно это просто деталь реализации → плохой)