4

我打算用 Java 开发一个游戏,它会有很多听众(动作、键、鼠标等)。

我的问题是实现监听器的最佳方式是什么。

方法一:

this.addActionListener(new ActionListener() {
   // Overide methods go here
});

方法二:

创建一个新类(或多个类),它将实现 ActionListener 并具有用于不同游戏组件的方法(按钮、移动、任何其他需要 ActionListener 的东西)

所以,例如。如果我正在制作一个按钮,这样做会更好吗

JButton button = new JButton();
button.addActionListener(new ActionListener() {

});

或者

JButton button = new JButton();
button.addActionListener(new MyActionListener());

// MyActionListener
class MyActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        Object objectPressed = e.getSource();
        if(objectPressed.equals(button) {
          System.out.println("Hello World");
        }
    }
}

我可以看到两种方式的优势,方法 1 你可以直接看到该对象发生了什么,但是方法 2 你可以看到所有组件。

那么在开发更易于维护的大型应用程序时,将所有侦听器放在单独的类中,还是使用方法 1?

4

5 回答 5

3

就个人而言,我更喜欢许多听众而不是一个带有“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);
    }
}
于 2013-06-01T23:47:56.540 回答
2

首先,条款。在这两种情况下,您都在定义类,但在第一种情况下,它们被称为匿名内部类。你会发现一些文件,如MyClass$1.java.

从这个意义上说,我的(其他可能不同)规则将是

1) 仅将匿名内部类用于未重用的更简单操作。对于所有其他,使用“常规”类。

2) 仅在有意义时重用组件。如果您有两个含义截然不同的按钮,请不要尝试重用同一个侦听器。创建几个。例如,如果您有两个按钮(一个增量和一个减量),您可以重用同一个类,因为操作非常相似。如果您有多个带有此类按钮的值,请重用传递要在构造函数中修改的对象的类。但不要将按钮与“开始回合”按钮混合使用来增加值。


更新:

而且,顺便说一句,当你说:

我可以看到两种方式的优势,方法 1 你可以直接看到该对象发生了什么,但是方法 2 你可以看到所有组件。

查看所有组件可能看起来像是一个优势,但如果您的所有类都可以更改所有其他类,那么封装逻辑方式会更加困难。封装意味着一些额外的工作,但最终你会得到一个更易于维护的产品,这很重要。

于 2013-06-01T23:50:13.423 回答
2

就我个人而言,我更喜欢使用 AbstractActions,或者作为匿名内部类,或者更经常作为独立的独立类:

JButton myExitButton = new JButton(new MyExitAction());

例如,作为我的 MVC Swing 项目一部分的 Control 类将其作为其代码的一部分:

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;
   }

   // .....
}

而作为我所有 AbstractActions 基础的抽象类如下所示:

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();
   }

}

一个警告:请注意,我不是一个专业的程序员,而是一个业余爱好者,所以虽然我的想法对我有用,但它们可能并不代表该领域的绝对最佳。欢迎所有更正和建议。我上面的设计的一个弱点是我认为我正在以一种笨拙的方式“注入”我的动作。

于 2013-06-02T00:30:04.577 回答
0

你也可以看看我一直在研究的这个名为 swingobjects 的摇摆框架。

https://github.com/Sethuraman/swingobjects

如果您使用 FrameFactory 类创建 Jframe,swingobjects 将为您在框架中声明的所有小部件注册一个 GlobalListener。这允许您做的是,在您的框架中使用如下注释标记一个方法:

@Action("<action name or button text>")
public void performAction(ActionEvent evt){
....
}

GlobalListener 将通过反射调用此方法。这意味着,您不必编写 if 块,创建匿名内部类。一切都为您透明地处理。看看框架...

于 2013-06-02T04:19:48.203 回答
0

老实说,我更喜欢第一个。你是对的第一种方法,你可以很容易地看到那个组件发生了什么。然而。有时按钮可能具有相同的行为或相同的 ActionListener,据说我更喜欢方法 2。因此您可以轻松地重用 actionListener。

于 2013-06-01T23:59:21.327 回答