Обработка событий в сложных приложениях - PullRequest
3 голосов
/ 20 ноября 2011

В настоящее время я пытаюсь разработать простой блокнот на Java. Однако я борюсь с правильной обработкой слушателей событий. Я придерживаюсь принципа единой ответственности при программировании. К сожалению, текущий способ обработки слушателей событий, безусловно, нарушает этот принцип.

Каждый раз, когда я создаю новую кнопку меню, мне нужно реализовать ActionListener, переопределить метод actionPerformed () и передать его в качестве аргумента метода addActionListener (). В результате весь код становится все более сложным и нарушает принцип единой ответственности, поскольку слушатели событий не отделены от пользовательского интерфейса.

Проблема становится более серьезной, когда нужно обработать множество компонентов. Таким образом, обработка 70 или 100 компонентов приведет к путанице во всем коде.

Это код, о котором я говорю:

menuButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(menuButton, "Message");
    }
});

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

Я посмотрел на шаблон Observer, но мне не удалось использовать его таким образом, чтобы не нарушать принцип единой ответственности.

Как бы вы обработали обработчики событий в моем приложении? Знаете ли вы, как обработчики событий обрабатываются в профессиональных и сложных приложениях, таких как MS Office или серьезных программах, написанных на Java?

package notepad;

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

public class Buttons extends MenuButtonListener {

// The menu buttons
private JMenuItem openFile, saveFile, saveAs, close;

// Get the saveFile field
public JMenuItem getSaveFile() {
    return saveFile;
}

/**
 * Creates the items of the file menu
 * @return JMenu
 */ 
public JMenu createFileMenuItems() {

    JMenu file = new JMenu("File");
    openFile = new JMenuItem("Open");
    saveFile = new JMenuItem("Save", KeyEvent.CTRL_MASK);
    saveAs = new JMenuItem("Save as");
    close = new JMenuItem("Close");

    // Add the listener to the button
    saveFile.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(saveFile, "Message");
        }
    });

    saveFile.setMnemonic(KeyEvent.VK_T);
    saveFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
            ActionEvent.CTRL_MASK));

    file.add(openFile);
    file.add(saveFile);
    file.add(Separators.addSeparator());
    file.add(saveAs);
    file.add(close);

    return file;

}

/**
 * Creates the items of the edit menu
 * @return JMenu
 */ 
public JMenu createEditMenuItems() {

    JMenu edit = new JMenu("Edit");
    JMenuItem cut = new JMenuItem("Cut");
    JMenuItem copy = new JMenuItem("Copy");
    JMenuItem paste = new JMenuItem("Paste");
    JMenuItem find = new JMenuItem("Find");

    edit.add(cut);
    edit.add(copy);
    edit.add(paste);
    edit.add(Separators.addSeparator());
    edit.add(find);

    return edit;
}

/**
 * Creates the items of the format menu
 * @return JMenu
 */ 
public JMenu createFormatMenuItems() {

    JMenu format = new JMenu("Format");

    return format;
}

/**
 * Creates the items of the help menu
 * @return JMenu
 */ 
public JMenu createHelpMenuItems() {
    JMenu help = new JMenu("Help");

    return help;
}

/**
 * Gets the specified menu item
 * @return JMenuItem
 */ 
public JMenuItem getMenuItem(JMenuItem menuItem) {
    return menuItem;
}
}
// This class should be used to handle the event listeners
package listeners;

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

public class MenuButtonListener  {

// Create an inner class for every button
public class SaveButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        Buttons buttons = new Buttons();
        JMenuItem saveButton = buttons.getSaveFile();
        if (e.getSource() == saveButton) {
            JOptionPane.showMessageDialog(saveButton, "Save");
        }
    }
}

public SaveButtonListener returnSaveButton() {
        return new SaveButtonListener();
    }


}

Ответы [ 3 ]

1 голос
/ 20 ноября 2011

Для такого сценария вы должны использовать Mediator Pattern, он полностью отделяет ваш пользовательский интерфейс от контроллера (вашего слушателя), очень хороший пример .

Позвольте мне расширить пример из ссылки на приложение для блокнота.

Вы можете иметь одну команду, контроллер для вашего «Файлового меню», которая позаботится обо всех файловых операциях, таких как «Новый», «Открыть» e.t.c, и другой контроллер для вашего, скажем, меню «Настройки». Теперь при создании меню «Файл» вы регистрируете его с помощью медиатора, говорящего registerView(JComponent component, String component_type), где компонент - это JMenu, компонент_типа - «ФАЙЛ», посредник может посмотреть, назначить ли соответствующий контроллер для представления, это отображение представления для контроллера может быть трудным закодированное значение (для блокнота вы можете иметь его внутри, скажем, на карте) или можно прочитать из файла конфигурации (например, xml конфигурации приложения, где вы определяете что-то вроде:

<application_config>
   <view_controller_mapping> 
      <view_name>FILE</view_name>
      <controller_name>FileController</controller_name><!--Optional-->            
      <controller_class>com.mycompany.notepad.view.controller.FileController</controller_class>
      <!--Incase you want to give control to others to provide there own implementation -->  
   </view_controller_mapping>
</application_config>

Надеюсь, это поможет.

0 голосов
/ 20 ноября 2011

Мне кажется, вы бы выиграли от использования MVC или MVP для структурирования вашего кода дисплея и логики слушателя. Взгляните на этот другой вопрос SO , чтобы узнать обо всех. Лично я предпочитаю MVP, и хотя он часто ассоциируется с ASP.NET, MVP на самом деле просто отличный шаблон для любого языка, включая Java. Я использую его в любое время, когда мне нужно работать с графическим интерфейсом, потому что он поддерживает SRP и максимизирует тестируемость. Сверхурочные затраты немного, но я думаю, что это того стоит, что дает MVP.

0 голосов
/ 20 ноября 2011

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

menuButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        showMessage();
    }
});

private void showMessage() {
    JOptionPane.showMessageDialog(frame, "Message");
}
...