Event Dispatcher / Listener - Interface Stil ...



  • Ich hatte grad eine Diskussion mit meinem Chef wie unser recht weit verbreitetes Event system überarbeitet werden sollte.
    Ausgangslage: Suboptimales System mit Dispatcher / Listener / Event Basisklasse, alle Event gehen als "Event *" raus und werden per dynamic_cast in den Listener in den "richtigen" Typ gecastet und verwendet wie gewünscht - oder verworfen. Unötiger overhead, bei entsprechender Eventvielfalt unübersichtlich ...

    Nachdem wir nun überhaupt mal einig sind, dass das so Scheisse war will mein Chef jetzt ins andere extrem: Für jeden Furz ein eigener Event Typ, einen eigenen Event-callback( selbst wenn beim Event durch einen simplen enum kein Unterschied gemacht werden müsste ).
    Find ich beinahe genauso deppert wie die Variante davor. Wie seht ihr das? Code unten zur Illustration.

    Ich glaub das "Grundproblem" ist das mein Chef einfache Regeln und klare Vorgaben so gern hat. Hauptsache niemand macht sich irgendwelche Gedanken wenn er ein Interface entwirft ....

    class SomeOtherObject
    {
    	//... something
    };
    
    class EventA
    {
    public:
    	enum EventTypeA
    	{
    		Type1,
    		Type2,
    		Type3,
    		Type4,
    		Type5,
    		Type6,
    	};
    	SomeOtherObject o;
    	EventTypeA t;
    };
    
    class EventB
    {
    public:
    	SomeOtherObject o;
    };
    
    class ListenerInterfaceA
    {
    	virtual void processEventA( EventA * const _eventA ) = 0;
    };
    
    class ListenerInterfaceB
    {
    	virtual void processEventBType1( EventB * const _eventB ) = 0;
    	virtual void processEventBType2( EventB * const _eventB ) = 0;
    	virtual void processEventBType3( EventB * const _eventB ) = 0;
    	virtual void processEventBType4( EventB * const _eventB ) = 0;
    	virtual void processEventBType5( EventB * const _eventB ) = 0;
    	virtual void processEventBType6( EventB * const _eventB ) = 0;
    };
    
    class SomeListenerImplementationA : public ListenerInterfaceA
    {
    	virtual void processEventA( EventA * const _eventA )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventA->o << " and type is " << _eventA->t << std::endl; 
    
    		switch( _eventA->t )
    		{
    		case EventA::Type1:
    			// wake up
    			break;
    		case EventA::Type2:
    			// eat something
    			break;
    		case EventA::Type3:
    			// do nothing
    			break;
    		case EventA::Type4:
    			// do nothing
    			break;
    		case EventA::Type5:
    			// get drunk
    			break;
    		case EventA::Type6:
    			// go sleeping
    			break;
    		}
    	}
    };
    
    class SomeListenerImplementationB : public ListenerInterfaceB
    {
    	virtual void processEventBType1( EventB * const _eventB )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventB->o << " and type is 1 " << std::endl; 
    		// wake up
    	}
    
    	virtual void processEventBType2( EventB * const _eventB )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventB->o << " and type is 2 " << std::endl;
    		// eat something
    	}
    
    	virtual void processEventBType3( EventB * const _eventB )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventB->o << " and type is 3 " << std::endl;
    		// do nothing
    	}
    
    	virtual void processEventBType4( EventB * const _eventB )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventB->o << " and type is 4 " << std::endl;
    		// do nothing
    	}
    
    	virtual void processEventBType5( EventB * const _eventB )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventB->o << " and type is 5 " << std::endl;
    		// get drunk
    	}
    
    	virtual void processEventBType6( EventB * const _eventB )
    	{
    		std::cout << "hey, we got some event here! o is: " << _eventB->o << " and type is 6 " << std::endl;
    		// go sleeping
    	}
    };
    


  • flicky schrieb:

    Basisklasse, alle Event gehen als "Event *" raus und werden per dynamic_cast in den Listener in den "richtigen" Typ gecastet und verwendet wie gewünscht - oder verworfen. Unötiger overhead, bei entsprechender Eventvielfalt unübersichtlich ...

    Wenn man den Code unten sieht ist aber der dynamic_cast unnötig! Der Type wird eh mit einem "event->t" bekannt. Wenn der type vom jeweiligen Konstruktor gesetzt wird sollte der Typ einwandfrei bestimmt sein, dann ist auch ein static_cast möglich der keinen Overhead mit sich bringt.

    Ansonsten gibt es doch genügend große Fraimworks (Qt, wxWidgets, z.B.) die scheinbar ein funktionierendes Event-System integriert haben. Warum dort nicht spicken?



  • Ich kann folgendes empfehlen (Functor-Realisierung):

    Zu jedem Event-Type gibt es eine Functor-Liste (Empfänger-Liste).
    Das Event-System dispatcht genau einmal und läuft dann die Functor-Liste durch.


Anmelden zum Antworten