Есть ли лучшая практика для слушателей?
Вопрос
Скажи, что у меня есть качающийся графический интерфейс, и я хочу послушать MouseEvents
. Анкет Как вы думаете, кто должен быть класс слушателей, кто должен нести ответственность? Какой лучший способ его реализовать? Есть мнения? Я обычно делаю так:
public class MyPanel extends JPanel implements MouseListener{
private JTable table;
public void foo(){
table.addMouseListener(this);
}
/* MouseListener */
//Implement MouseListener here.
}
Есть ли способ лучше?
РЕДАКТИРОВАТЬ: Спасибо всем за мудрость и помощь. Я ценю это.
Решение
Есть несколько распространенных способов сделать слушателей событий (единственные, о которых я могу подумать, что я остановил в коде ниже, - это статические внутренние классы). Приведенный ниже код использует ActionListener, так как он самый простой, но вы можете применить эту идею к любому слушателю.
Обратите внимание, что «этот» способ (реализация класса) может привести к огромному набору операторов, если/иначе. Я бы сказал, что это худший способ из -за этого. Мне не нравится иметь методы «очистки дома» по двум причинам:
1) Они большие 2) Собкачительно выполнять работу внутри метода, а не иметь каждый, если/иначе вызовет метод для выполнения работы (что, как вы можете видеть, это то, что я сделал здесь ... упс: -)
Мне также не нравится анонимный путь по двум причинам:
1) Вы не можете легко повторно использовать код, чтобы вы могли обнаружить, что у вас есть дублированный код через некоторое время 2) Я обнаружил, что он разбивает чтение кода (другие не согласны ... личный вкус). Я думаю, что все согласятся с тем, что если вы делаете более 5-10 строк, анонимный внутренний класс-не очень хорошая идея (я бы сказал, что более 2-это слишком много).
Это оставляет внутренние и внешние способы. Я бы использовал внешний путь, когда пишу слушателя, который не тесно связан с графическим интерфейсом, который он слушает. Если слушатель не нуждается в информации (переменные членов/методы), которые являются частью класса (в данном случае testframe), я бы выбрал внешний класс. В приведенном ниже примере я прошел в «This», чтобы внешние слушатели могли получить доступ к графическому интерфейсу ... если бы я писал код, так, я бы вместо этого сделал его внутренним классом, так как это требует чего -то из графического интерфейса.
Итак, мой заказ предпочтения:
- Внутренний класс (статический, если это возможно, но если вы делаете его статичным, я бы пошел на внешний класс)
- Внешний класс
- анонимный внутренний класс (редко)
- Попросите класс реализовать это сам (никогда бы я этого не делал. Никогда!)
И вот код
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
final TestFrame frame;
frame = new TestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(new Rectangle(10, 10, 300, 300));
frame.init();
frame.setVisible(true);
}
}
class TestFrame
extends JFrame
implements ActionListener
{
private final JButton aBtn;
private final JButton bBtn;
public TestFrame()
{
super("Test");
aBtn = new JButton("A");
bBtn = new JButton("B");
}
public void init()
{
setLayout(new FlowLayout());
add(aBtn);
add(bBtn);
// the class, since it implements ActionListener
aBtn.addActionListener(this);
bBtn.addActionListener(this);
// outer classes
aBtn.addActionListener(new OuterAListener(this));
bBtn.addActionListener(new OuterBListener(this));
// inner class
aBtn.addActionListener(new InnerAListener());
bBtn.addActionListener(new InnerBListener());
// anonymous classes
aBtn.addActionListener(
new ActionListener()
{
public void actionPerformed(final ActionEvent e)
{
System.out.println ("Hi from Anonymous A");
}
});
bBtn.addActionListener(
new ActionListener()
{
public void actionPerformed(final ActionEvent e)
{
System.out.println ("Hi from Anonymous B");
}
});
}
public void actionPerformed(final ActionEvent evt)
{
final Object source;
source = evt.getSource();
if(source == aBtn)
{
System.out.println ("Hi from this A");
}
else if (source == bBtn)
{
System.out.println ("Hi from this B");
}
else
{
// ???
}
}
private class InnerAListener
implements ActionListener
{
public void actionPerformed(final ActionEvent e)
{
System.out.println ("Hi from Inner A");
}
}
private class InnerBListener
implements ActionListener
{
public void actionPerformed(final ActionEvent e)
{
System.out.println ("Hi from Inner B");
}
}
}
class OuterAListener
implements ActionListener
{
private final TestFrame frame;
public OuterAListener(final TestFrame f)
{
frame = f;
}
public void actionPerformed(final ActionEvent e)
{
System.out.println ("Hi from Outer A");
}
}
class OuterBListener
implements ActionListener
{
private final TestFrame frame;
public OuterBListener(final TestFrame f)
{
frame = f;
}
public void actionPerformed(final ActionEvent e)
{
System.out.println ("Hi from Outer B");
}
}
Другие советы
Я бы посоветовал поставить слушателя в свой собственный класс, сделать его повторным использованием и иметь четкое разделение проблем
Посмотрите на код качания Java. Это действительно лучшее место, чтобы увидеть хорошие стандарты.
В вашем случае у меня будет что -то вроде:
public class MyPanel extends JTable {
public void foo() {
addMouseListener(new MouseHandler() );
}
private class MouseHandler implements MouseListener {
...
}
}
Таким образом, у вас есть четкое разделение функциональности. Когда ваш основной класс начнет реализовывать пятнадцать различных интерфейсов, ваш код станет совершенно незаметным.
Анонимные классы в основном используются для слушателей. Если вы знаете, что у вас есть конкретный слушатель, зарегистрированный только один раз, и он довольно короткий, то вы можете использовать анонимный класс.
Лично мне нравится отделить свой графический интерфейс от контроллеров. Поэтому я предложу внедрить слушателя в классе контроллера (каждый функциональный графический интерфейс имеет свои собственные) и работать там, даже необходимо использовать if...else
или же swich...case