我目前正在尝试用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();
}
}
答案 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提供的好处是值得的。