Java ActionListeners
我将用Java开发一个游戏,它将有许多监听器(动作、键、鼠标等) 我的问题是实现侦听器的更好方法是什么 方法1:Java ActionListeners,java,swing,jbutton,actionlistener,anonymous-inner-class,Java,Swing,Jbutton,Actionlistener,Anonymous Inner Class,我将用Java开发一个游戏,它将有许多监听器(动作、键、鼠标等) 我的问题是实现侦听器的更好方法是什么 方法1: this.addActionListener(new ActionListener() { // Overide methods go here }); 方法2: 创建一个新类(或多个类),该类将实现ActionListener,并具有用于不同游戏组件(按钮、移动、任何其他需要ActionListener的组件)的方法 比如说。如果我在做一个按钮,是不是更好 JButton
this.addActionListener(new ActionListener() {
// Overide methods go here
});
方法2:
创建一个新类(或多个类),该类将实现ActionListener,并具有用于不同游戏组件(按钮、移动、任何其他需要ActionListener的组件)的方法
比如说。如果我在做一个按钮,是不是更好
JButton button = new JButton();
button.addActionListener(new ActionListener() {
});
或
我可以从两个方面看到优势,方法1可以直接看到对象发生了什么,但方法2可以看到所有组件
因此,当开发更易于维护的大规模应用程序时,将所有侦听器放在单独的类中,或者个人使用方法1?时,我更喜欢多个侦听器,而不是带有“if”检查的侦听器。这将允许我独立地修改它们 我会将代码嵌入UI中。我会将它们作为单独的类编写,并使用构造函数或DI工厂将它们作为依赖项注入 构造函数注入:
public class YourPanel extends JPanel {
private JButton button;
public YourPanel(ActionListener buttonListener) {
this.button = new JButton("Do It");
this.button.addActionListener(buttonListener);
}
}
第一,条款。在这两种情况下,您都在定义类,但在第一种情况下,它们被称为匿名内部类。您会发现一些文件,如
MyClass$1.java
从这个意义上说,我的(其他人可能不同)规则是
1) 仅将匿名内部类用于不可重用的简单操作。对于所有其他类,使用“常规”类
2) 只有当组件有意义时才重用它们。如果您有两个含义完全不同的按钮,请不要尝试重复使用同一个侦听器。创建几个。例如,如果您有两个按钮(递增和递减),您可以重用同一个类,因为操作非常相似。如果有多个带有此类按钮的值,请重用传递要在构造函数中修改的对象的类。但不要将增加值的按钮与“开始循环”按钮混合使用
更新: 顺便说一下,当你说: 我可以从两个方面看到优势,方法1可以直接看到对象发生了什么,但方法2可以看到所有组件
查看所有组件似乎是一种优势,但如果所有类都可以更改其他所有组件,则封装逻辑的方式将更加困难封装意味着一些额外的工作,但最终您会得到一个更易于维护的产品,这是一件重要的事情。老实说,我更喜欢第一个。你是对的,第一种方法你可以很容易地看到该组件发生了什么。然而。有时按钮可能具有相同的行为或相同的ActionListener,也就是说我更喜欢方法2。因此,您可以轻松地重用actionListeners。我自己只想再添加一条线索,我更喜欢使用AbstractActions,或者作为匿名内部类,或者更经常地作为独立的独立类:
JButton myExitButton = new JButton(new MyExitAction());
例如,作为我的MVC Swing项目一部分的控件类的代码中包含以下内容:
public class Control {
// these two types below are interfaces
private Model model;
private View view;
public Control(Model model, View view) {
this.model = model;
this.view = view;
addViewListeners();
}
private void addViewListeners() {
view.setGetPageAction(new GetPageAction(this, "Get Page", KeyEvent.VK_G));
view.setSetTnRendererBtnAction(new SetTnRendererBtnAction(this, "Show Images", KeyEvent.VK_S));
view.setClearThumbNailsAction(new ClearThumbNailsAction(this, "Clear ThumbNails", KeyEvent.VK_C));
view.setSetDestinationAction(new SetDestinationAction(this, "Set Destination", KeyEvent.VK_T));
view.setDownloadAction(new DownloadAction(this, "Download", KeyEvent.VK_D));
view.setExitAction(new ExitAction(this, "Exit", KeyEvent.VK_X));
model.addPropertyChangeListener(new ModelListener());
}
public View getView() {
return view;
}
public Model getModel() {
return model;
}
// .....
}
作为我所有抽象操作基础的抽象类如下所示:
public abstract class MyAbstractAction extends AbstractAction {
protected Control control;
protected Model model;
protected View view;
public MyAbstractAction(Control control, String txt, int mnemonic) {
super(txt);
putValue(MNEMONIC_KEY, mnemonic);
this.control = control;
this.model = control.getModel();
this.view = control.getView();
}
}
一个警告:注意我不是一个专业的程序员,而是一个业余爱好者,所以虽然我的想法对我有用,但它们可能并不代表这个领域的绝对最佳。欢迎所有更正和建议。我上面设计的一个缺点是,我认为我正在以一种笨拙的方式“注入”我的动作。您也可以看看我一直在开发的名为swingobjects的swing框架 如果使用FrameFactory类创建Jframe,swingobjects将为您在框架中声明的所有小部件注册一个GlobalListener。这允许您做的是,在框架中用如下注释标记一个方法:
@Action("<action name or button text>")
public void performAction(ActionEvent evt){
....
}
@操作(“”)
公共无效执行(ActionEvent evt){
....
}
GlobalListener将通过反射调用此方法。这意味着,您不必编写if块,而是创建匿名内部类。一切都是透明地为您处理的。查看一下框架…感谢您的更新!请看一下我的答案。我做了类似的事情,但我觉得必须有更好的方法来做,使用某种间接寻址,也许是一个配置文件,以防止我必须硬编码这种注入。再次感谢。我认为更好的方法是使用像Spring或Guice这样的DI引擎。谢谢,我将对此进行研究。我一直认为Spring主要用于企业服务器,但肯定有比我意识到的更多的东西。“请注意,我不是一个专业的程序员,而是一个最爱编程的人。”这让我感到惊讶,因为我一直喜欢你的答案。@duffymo:谢谢。我想我需要仔细阅读注释,因为这可能会帮助我解决注入问题。
AbstractAction
s唯一不喜欢的是在每个注释之前需要的@SuppressWarnings(“序列”)
,或者整个方法(这是个坏主意)。当然,这只有在匿名的情况下才会发生。对我来说,规则#1略有不同:它总是使用匿名的内部类,但如果是较大的代码块,则委托给封闭类中的方法。因此,侦听器可能只运行cardLayout.show(OuterClass.this,“HOME\u VIEW”)
,但会委托给performSave()
。
@Action("<action name or button text>")
public void performAction(ActionEvent evt){
....
}