Java ActionListeners

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

我将用Java开发一个游戏,它将有许多监听器(动作、键、鼠标等)

我的问题是实现侦听器的更好方法是什么

方法1:

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){
....
}