4

複数の Menu と MenuItem を含む 1 つのクラス (MenuBarClass と呼びましょう) があります。すべての MenuItem に actionlistener を割り当てたいのですが、次のようなことをする代わりに:

menuitem_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
menuitem_2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
menuitem_3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });
// ...
menuitem_N.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {} });

私は自分のコードをもっと管理しやすくしたい..もっと重要..次のような1つの巨大なActionListenerクラスにたくさんの「if」を入れたくない:

public void actionPerformed(ActionEvent e) {
  if (e.getSource().equals(menuitem_1)) {
    //do stuff..
  } else if (e.getSource().equals(menuitem_2)) {
    //do stuff..
  } else ...
}

可能であれば、どうすればこれを行うことができますか? 誰でも助けることができますか?

4

4 に答える 4

2

リフレクションAPIを使用して冗長性を減らし、ユーティリティメソッドを作成できます。

package demo;    
import java.awt.event.*;
import java.lang.reflect.*;

public class ListenerProxies {    
  private static final Class<?>[] INTERFACES = { ActionListener.class };

  public static ActionListener actionListener(final Object target,
                                                    String method) {
    final Method proxied = method(target, method);
    InvocationHandler handler = new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
        ActionEvent event = (ActionEvent) args[0];
        return proxied.invoke(target, event);
      }
    };
    return (ActionListener) Proxy.newProxyInstance(target.getClass()
        .getClassLoader(), INTERFACES, handler);
  }

  private static Method method(Object target, String method) {
    try {
      return target.getClass().getMethod(method, ActionEvent.class);
    } catch (NoSuchMethodException e) {
      throw new IllegalStateException(e);
    } catch (SecurityException e) {
      throw new IllegalStateException(e);
    }
  }
}

これは次のように利用できます。

package demo;
import static demo.ListenerProxies.actionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class Demo {

  public static void main(String[] args) {
    Demo test = new Demo();
    JButton hello = new JButton("Say Hello");
    hello.addActionListener(actionListener(test, "sayHello"));
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(hello);
    frame.pack();
    frame.setVisible(true);
  }

  public void sayHello(ActionEvent event) {
    System.out.println("Hello");
  }
}

これの欠点は、sayHello(ActionEvent)メソッドが存在することをコンパイル時にチェックできないことです。

パフォーマンスコストはごくわずかです。

于 2012-04-22T21:16:01.037 に答える
1

実際には、これらのActionListenerオブジェクトは、コマンド デザイン パターンによるコマンド オブジェクトです。匿名サブクラスの代わりにカスタム サブクラスを作成して、もう少しエレガントにすることができます。

アクション リスナーとコマンド オブジェクトをどのように接続するかが気になる場合は、リフレクションを使用して次のようにします。

  • @MenuAction適切なコマンド オブジェクトのクラスを取るようなカスタム アノテーションを作成します。
  • このコマンドを読み取り、インスタンス化し、実行する汎用アクション リスナーを作成します。
  • すべてのメニュー項目に汎用アクション リスナーを追加します。

よく考えれば、フレームワークを作成して、この一般的なアプローチを複数のプロジェクトで使用することもできますが、適切なActionListener実装でいくつかのメニュー項目を手動で配線するよりもはるかに多くの作業が必要になります。

于 2012-04-22T21:02:48.330 に答える
1

やりたいことがすべてのメニュー項目で似ている場合は、ActionListenerコンストラクター引数を取るクラス実装を作成できます。たとえば、各メニュー項目を開く必要があるJFrame場合は、次のようにすることができます。

public class OpenFrameAction implements ActionListener
{
    private final JFrame frame;

    public OpenFrameAction(final JFrame frameToOpen)
    {
        this.frame = frameToOpen;
    }

    public void actionPerformed(ActionEvent e)
    {
        this.frame.setVisible(true);
    }
}

そして、各メニュー項目について:

menuitem_1.addActionListener(new OpenFrameAction(myFrameForMenuItem1));
于 2012-04-22T21:06:19.270 に答える
0

siegiの答えを拡張します。実行するアクションに共通点がある場合 (崖から飛び降りる、タンゴを演奏する、コーヒーを飲む) のみ、個々のリスナーを各項目に追加する必要があります。この場合、Java がメンテナンスの魔法を実行することは期待できません。

より一般的なケースは、アクションに共通点がある場合です (タンゴを行う、フォックストロットを行うなど)。このような場合は、siegi のアドバイスに従うか、(項目ではなく) メニューにリスナーを追加します。イベントは、どの項目が選択されたかを通知する必要があり、それをリスナーで使用できます。

// something like this
actionPerformed(ActionEvent e)
{
    this.doDance(e.getSource().getSelectedValue());
}
于 2012-04-22T21:27:17.243 に答える