2011-01-04 5 views
1

私のプログラムでは、投げ捨てられた50のイベントに近いものがあります。私が持っている問題は、イベントを受け取るための標準的な方法で解決しています。イベントのトン、コードベースを縮小する方法?

私の最初の考えは、汎用インターフェースを使用して、リスナーにこれを実装させ、リスナーのキューに自分自身を追加させることでした。 Unfortunately this meant that classes couldn't have multiple listeners due to type erasure and multiple inheritance issues。そこで、リスナーコードを削除して、やり直しました。

私の現在の(そしてオリジナルの)設定は、各イベントをリスナーするインターフェースを持つことです。例えば

/** 
* Listener for {@link myproject.hooks.events.FingerEvent}events 
* @see myproject.hooks.events.Finger 
*/ 
public interface FingerListener extends Listener { 
     /** 
     * Invoked when an {@link myproject.hooks.events.FingerEvent}occurs 
     * @param event The generated FingerEvent 
     */ 
     public void onFinger(FingerEvent event); 
} 

は、彼らはすべて彼らはすべて総称して「リスナー」と呼ばれることができ、そのちょうどように、任意のメソッドが含まれていないインターフェイスListenerを拡張します。

この問題は、1イベントにつき1トンのコードがあることです。あなたはイベントとそのゲッターを持っています(これはProject Lombokによってうまくいけば簡単にできました)。そして、それを受け取るインターフェース、次にjavadocをインターフェース上に持っています。

私が持っているもう1つの問題は、各リスナーには異なるメソッド名があり、どのメソッドを呼び出すかを把握しようとする非常に興味深いコードにつながるということです。その壊れやすい、遅い(反射を使用して)、とらくすように見えます。あなたはその後、私を信じていない場合:

public static boolean callListener(Event event, Listener listener) {    
      //Get base name of event 
      String name = event.getClass().getSimpleName().split("Event")[0]; 

      //Try and get the correct method if it exists 
      Method listenerMethod = null; 
      try { 
        listenerMethod = listener.getClass().getMethod("on"+name, event.getClass()); 
      } catch (NoSuchMethodException ex) { 
        //Method doesn't exist, just don't call anything 
        return false; 
      } catch (SecurityException ex) { 
        throw new RuntimeException("Method on"+name+" is unaccessable", ex); 
      } 

      //Now that we have the method, attempt to execute it 
      try { 
        listenerMethod.invoke(listener, event); 
      } catch (Exception ex) { 
        throw new RuntimeException("Unexpected error when invoking method on"+name); 
      } 

      //Method executed sucessfully, return true 
      return true; 
    } 

これはかかわらず、Javaでイベントを受信するための標準的な方法です。そして、適切なメソッドを呼び出すためにスパゲッティを作成、または私はこれをやっている各イベントのリスナーインタフェースを持っています完全に間違っている?

答えて

2

少なくとも、イベント処理をリスナーに委譲することを単純化することで、リフレクション/呼び出し論理を取り除くことができます。

public interface Listener { 
    public boolean process(Event event); 
} 

と、このようなコード変更:今すぐ

public static boolean callListener(Event event, Listener listener) { 
    return listener.process(event); 
} 

を私たちは持っている場合、リスナーは同じように、あなたのマーカーインタフェースへの一つの方法を追加しますので、それは、処理できるイベントの種類を知っていますイベントBreakfastDinnerを理解し、リスナー、我々は(MealListenerで)このようにそれを実装することができます

public class MealListener implements Listener { 

    @Override 
    public boolean process(Event event) { 
    if (event instanceof Breakfast) { 
     this.onBreakfast((Breakfast) event); 
     return true; 
    } 
    if (event instanceof Dinner) { 
     this.onDinner((Dinner) event); 
     return true; 
    } 
    return false; // MealListener ignores this event 
    } 

    private void onBreakfast(Breakfast breakfastCall) { 
    // eat breakfast 
    } 

    private void onDinner(Dinner dinnerCall) { 
    // eat dinner 
    } 

} 

ところで、 "たくさんのクラス"を恐れてはいけません。すべてのイベントとリスナーに共通のソースパターンを見つけ、ソースファイルを自動生成します。この場合、個々のイベントとリスナーのソースファイルを維持する必要はなく、コードジェネレータとそのリソースファイル(すべてのイベントとリスナーのベース名を持つファイルベースのリスト)

+0

これは面白い方法です。 MealListenerは私が作成する具体的なクラスですか? – TheLQ

+0

MealListenerは作成するクラスです。あなたがいくつかのリスナーが朝食と夕食に応答して別のことをやりたければ、それは抽象的である可能性があります。 –

+0

@Carlこれは、人が複数のイベントを聞きたいときに複雑になるようです。おそらく私がこれをやろうとしていたのであれば、イベントと単一のListenerインターフェイスを提供し、実装が必要なイベントにキャストされます。 – TheLQ

0

デザインが間違っています。どのクラスがイベントを発生させていても、インタフェースに定義されているメソッドを呼び出す必要があります。

だからあなたのインターフェイスがこのようなものになります。

 
public interface FingerListener { 
    public void listenerCallback(FingerEvent event); 
} 

をそしてあなたは単にあなたのリスナーを反復処理し、各登録リスナーのlistenerCallbackメソッドを呼び出すことができます。

受信者が異なる種類のイベントを区別する必要がある場合は、受信者が検査できるFingerEventクラスに "type code"プロパティを追加します。

+0

'listenerCallback'スーパーインターフェース 'Listener'で使用するか、すべてのListenerクラスに対してローカルにしておきますか? – TheLQ

+0

あなたは基本インターフェースでそれを定義する必要があるので、あなたのケースではListenerクラスになります(私はそれがある理由はわかりませんが) –

関連する問題