15

以下では、EventHandler が EventA をある方法で処理し、EventB を別の方法で処理し、他のすべてのイベント (EventC、EventD) をさらに別の方法で処理するようにします。EventReceiver は Event への参照のみを受け取り、EventHandler.handle() を呼び出します。もちろん、常に呼び出されるバージョンは EventHandler.handle(Event event) です。

instanceOf を使用せずに、(おそらく EventHandler またはジェネリックの別のメソッドを介して) 適切なハンドル メソッドにポリモーフィックにディスパッチする方法はありますか?

class EventA extends Event {
}

class EventB extends Event {
}

class EventC extends Event {
}

class EventD extends Event {
}

class EventHandler {
    void handle(EventA event) {
       System.out.println("Handling EventA");
    }

    void handle(EventB event) {
       System.out.println("Handling EventB");
    }

    void handle(Event event) {
       System.out.println("Handling Event");
    }
}

class EventReceiver {
    private EventHandler handler;

    void receive(Event event) {
        handler.handle(event);
    }
}    
4

5 に答える 5

14

Visitor パターン(の変形) を適用するケースのように思えます。(C++、C#、Java などの主流の OO 言語では、メソッドは単一ディスパッチです。つまり、一度に 1 つの型に対してのみポリモーフィックにできます。ビジターでは、二重ディスパッチを実装できます。)

Eventただし、これにはクラスも変更できる必要があり、 Events から (の基本インターフェース) への依存関係が作成されますEventHandler

class EventA extends Event {
  public handleBy(EventHandler eh) {
    eh.handleEventA(this);
  }
}

class EventB extends Event {
  public handleBy(EventHandler eh) {
    eh.handleEventB(this);
  }
}

class EventHandler {
    void handleEventA(EventA event) {
       System.out.println("Handling EventA");
    }

    void handleEventB(EventB event) {
       System.out.println("Handling EventB");
    }

    void handle(Event event) {
       event.handleBy(this);
    }
}
于 2011-01-19T15:52:58.850 に答える
2

これはdouble-dispatchの使用例です。いいえ (実際に知っているように、どちらも Visitor と呼ばれます) ? EventA のみの例を実装します

class Event {
    /**
     * Will do some type escalation
     */
    void handleWith(EventHandler care) {
        care.handle(this);
    }
}



class EventA extends Event {
    /**
     * As event is EventA, this implementation is called, with its correct type forced by the cast
     */
    void handleWith(EventHandler care) {
        care.handle((EventA) this);
    }
}

class EventHandler {
    /**
     * Finally comes here
     */
    void handle(EventA event) {
       System.out.println("Handling EventA");
    }

    void handle(EventB event) {
       System.out.println("Handling EventB");
    }

    void handle(Event event) {
       System.out.println("Handling Event");
    }

    /**
     * Go here first and dispatch call to Event class
     */
    void doHandle(Event event) {
        event.handleWith(this);
    }
}

class EventReceiver {
    private EventHandler handler;

    void receive(Event event) {
        handler.doHandle(event);
    }
}    
于 2011-01-19T15:56:40.500 に答える
2

Java は、メソッドが呼び出されるオブジェクトに対してのみポリモーフィック ディスパッチを行います。つまり、真のポリモーフィズムを実現する唯一の方法は、handle()メソッドをEventインターフェイス自体に配置することです。データオブジェクトを操作する「ハンドラー」はかなり手続き型であるため、実際にはそれが全体的に優れたオブジェクト指向ソリューションであると言えます。

他のソリューション (クラスをキーとするハンドラー オブジェクトのマップなど) は、特に継承に関して、より複雑で柔軟性が低くなります。

于 2011-01-19T15:58:20.763 に答える
0

私はあなたがいくつかの前処理でそれを行うことができる方法を知っています。次のようなものを使用します。

public abstract class EventHandler<T extends Event> {
   public abstract void handle(T event, Class<T> c);
   public abstract Class<T> handles();
}

public class EventHandlerA extends EventHandler<EventA> {
   @Override
   public void handle(EventA event, Class<EventA> c) {
      System.out.println(event);
   }

   @Override
   public Class<EventA> handles() {
      return EventA.class;
   }    
}

次に、マップを使用してハンドラーを整理します

HashMap<Class<?>,Collection<EventHandler<?>> handlers;

イベントを処理する必要がある場合は、マップからハンドラーを取得するだけです。Class.equals()およびClass.hashCode()が希望どおりに機能しない場合は、希望する動作を取得するためのラッパーが必要になります。

于 2012-12-17T19:34:52.307 に答える
0

Map を使用して、イベント タイプをイベント ハンドラにマップできます。

Map<Class<? extends Event>, Handler> map =
    new HashMap<Class<? extends Event>, Handler>();

void receive(Event event) {
    Handler handler = map.get(event.getClass());
    handler.handle(event);
}
于 2011-01-19T15:55:04.120 に答える