复杂应用程序中的事件处理

时间:2011-11-20 16:05:14

标签: java events listener

我目前正在尝试用Java开发一个简单的记事本。但是,我正在努力正确处理事件监听器。编程时我坚持单一责任原则。不幸的是,当前处理事件监听器的方式肯定违反了原则。

每次创建新的菜单按钮时,我都必须实现ActionListener并覆盖actionPerformed()方法并将其作为addActionListener()方法的参数传递。 结果,整个代码变得越来越复杂,并且违反了单一责任原则,因为事件监听器没有与UI分离。

当有许多组件要处理时,问题会变得更严重。 以这种方式处理70或100个组件会使整个代码混乱。

这是我正在谈论的代码:

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

我也尝试使用内部类来处理事件监听器,但是在CPU性能方面,为每个组件定义这么多内部类并不是一个好主意。

我看过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 个答案:

答案 0 :(得分:1)

对于这种情况,您应该使用Mediator Pattern,它将您的UI与控制器(您的监听器)完全分开,这是一个非常好的example

让我尝试将链接中的示例扩展到您的记事本应用程序。

你可以为你的'文件菜单'设置一个命令控制器,它负责所有文件操作,如'新','打开'e.t.c和另一个控制器,用于你的'设置'菜单。现在在创建菜单'文件'时,你用mediator注册它registerView(JComponent component, String component_type),其中组件是JMenu,component_type是'FILE',然后mediator可以看看为视图分配适当的Controller,这个视图到控制器的映射可以是硬编码值(对于记事本,你可以在里面说地图)或者可以从配置文件中读取(说一个应用程序配置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>

希望这有帮助。

答案 1 :(得分:0)

您要做的是将选择菜单时所发生的功能移动到单独的方法中,您的动作监听器现在唯一需要做的就是将菜单选择“粘合”到方法中。这样,您就可以使用菜单,按钮或程序的任何其他部分中的相同代码。

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

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

答案 2 :(得分:0)

在我看来,使用MVC或MVP来构建显示代码和监听器逻辑会让您受益匪浅。看看这个other SO question,了解两者的背景知识。就个人而言,我赞成MVP,虽然它经常与ASP.NET相关联,但MVP实际上只是包括Java在内的任何语言中的一个很好的模式。我随时都需要使用GUI来使用它,因为它可以维护SRP并最大限度地提高可测试性。有一些样板开销,但我认为MVP提供的好处是值得的。

相关问题