Java: где я должен поместить анонимный код слушателя? - PullRequest
8 голосов
/ 15 января 2011

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

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // code here
    }
});

или

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        buttonPressed();
    }
});

private void buttonPressed() {
    // code here
}

Какой рекомендуемый способ с точки зрения удобочитаемости и ремонтопригодности? Я предпочитаю хранить код внутри слушателя, и только если он становится слишком большим, делайте его внутренним классом. Здесь я предполагаю, что код больше нигде не дублируется.

Спасибо.

Ответы [ 6 ]

4 голосов
/ 15 января 2011

Мое добровольное правило:

  1. Если у слушателя более двух методов, создайте именованный класс.
  2. Если слушатель занимает более 10 строк, создайте именованный класс.

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

2 голосов
/ 15 января 2011

На этот вопрос частично ответ здесь:

Есть ли лучшая практика для слушателей

Мне также не нравится анонимный способ по двум причинам:
1) Вы не можете легко повторно использовать код, поэтому через некоторое время вы можете обнаружить, что у вас есть дублирующийся код. 2) Я считаю, что это нарушает чтение кода (другие не согласны ... личный вкус). Я думаю, что все согласятся, что если вы делаете более 5-10 строк, то анонимный внутренний класс не очень хорошая идея (я бы сказал, что больше 2 - это слишком много).

1 голос
/ 15 января 2011

По моему личному опыту лучше всего следовать шаблону MVC.Таким образом, существует отдельный класс, представляющий модель, которая создает все соответствующие действия, прослушиватели действий и т. Д. Предпочтительно, чтобы действия были представлены как конечные поля класса, которые создаются в конструкторе.1003 *

public class Model {
    private final Action buttonAction;
    ...

    public Model(final IController controller) {
       buttonAction = createButtonAction(controller);
       ...
    }

    private Action createButtonAction(final IController controller) {
        Action action = new Action("Action") {
            public void actionPerformed(final ActionEvent e) {
                // do the required action with long running ones on a separate Thread
                controller.run();
            }
        };
        action.set...// other initialisation such as icon etc
        ...
        return action;
    }
    ...

    public Action getButtonAction() {
        return buttonAction;
    }
}

Представление также представлено отдельным классом, который принимает модель в качестве параметра конструктора, где происходит фактическое создание экземпляра кнопки.Например:

public class View extends JPanel {
    public View(final Model model) {
       ...
       JButton button = new JButton(model.getButtonAction();
       ...
    }
}

При таком подходе довольно удобно реализовывать логику actionPerformed как часть анонимного класса, поскольку его очень мало для повторного использования.Вся логика инкапсулирована в контроллере, поэтому действия действительно служат оболочкой для вызова контроллера, который используется в качестве модели для кнопки.

1 голос
/ 15 января 2011

Если к методу buttonPressed() когда-либо потребуется доступ из чего-либо, кроме анонимного внутреннего класса, используйте метод.В противном случае просто поместите код в actionPerformed().

1 голос
/ 15 января 2011

По моему личному мнению, "это зависит".Если слушатель должен быть добавлен только к одному компоненту, он очень прост и является неотъемлемой частью графического интерфейса, тогда анонимный внутренний класс будет работать хорошо.Если слушатель сложен, будет добавлен к нескольким компонентам, будет иметь свое собственное отдельное состояние, тогда лучше использовать отдельный отдельный класс.Между ними находится внутренний внутренний класс.HTH.

Редактировать: Мой плохой.Я отвечал на другой вопрос - использовать или нет отдельный отдельный класс для слушателя.Что касается того, сохранять ли внутренний код класса встроенным или в методе, я согласен с другим автором, это будет зависеть от размера и сложности кода слушателя.

0 голосов
/ 16 января 2011

Да, это сильно зависит от того, что вы пытаетесь сделать.Я думаю, что анонимные внутренние классы получили плохой рэп из-за двух мифов.Нельзя повторно использовать анонимный код.И во-вторых, утечки памяти.Но это легко исправить с помощью простого подхода.Сохраните ссылку на экземпляр.Для совместного использования кода просто создайте ссылку на анонимный внутренний класс.

Action action = new AbstractAction("Open") {...};
JButton button = new JButton( action );
JMenuItem menuItem = new JMenuItem( action );
panel.getActionMap().put("openFile", action );

Теперь вы можете повторно использовать это действие для нескольких компонентов.Для более поздней проблемы утечек памяти вы можете использовать эту ссылку, чтобы отменить ее регистрацию, или второй и более простой вариант - WeakListeners.Преимущество WeakListeners заключается в том, что им не нужно управлять после их создания.

Что касается стиля, я считаю, что прослушиватели Anonymous очень удобны, а в некоторых случаях их легче читать при работе с потоками в Swing, потому что они сохраняют вашкод в одном методе (invokeLater, executeInBackground и т. д.).Когда вы не делегируете слушателя в метод экземпляра, я думаю, что он разделяет код, в котором вы не можете прочитать то, что произошло до слушателя, и логику, связанную с слушателем, на одном экране.Они имеют тенденцию отделяться друг от друга, и за ними труднее следовать.

Следует иметь в виду, что при использовании ActionMaps большинство утечек памяти исчезнет, ​​связанных с прослушиванием с клавиатуры.К сожалению, такие вещи, как фокусные слушатели или слушатели, которые зарегистрированы в центральных системах, все еще остаются проблемой.(Опять же, WeakListeners здесь великолепны).И у вас уже есть место для сохранения действия с каждым компонентом, поэтому нет необходимости создавать дополнительные переменные экземпляра для его хранения.Если вам нужно повторно использовать два компонента (например, в строке меню и в элементе управления), создайте отдельный класс.

...