Klassendesign: IRC Client Library



  • Das sieht zwar grundsaetzlich gut aus, aber wie wuerden dann die Events funktionieren? Du hast hier ja nur einen Event-Typ, wie funktioniert das mit den verschiedenen Event-Arten?



  • Kellerautomat schrieb:

    Das sieht zwar grundsaetzlich gut aus, aber wie wuerden dann die Events funktionieren? Du hast hier ja nur einen Event-Typ, wie funktioniert das mit den verschiedenen Event-Arten?

    Was ich hier skizziert habe ist etwa das, wie ActionScript 3 das event Handling macht.

    Du kannst ruhig mehrer events haben.

    Event könnte zB so aussehen:

    class Event {
    private:
      EventData* data;
      EventType type; //eigentlich nur ein integer!
    
    public:
      Event(EventType type, EventData* data=0)
      : type(type), data(data) {}
    
      ~Event() { delete data; }
    
      bool isEqual(Event const& other) {
        return type == other.type;
      }
    
      EventData const* getData() const {
        return data;
      }
    };
    

    Wenn ich nun ein Join Event haben will, amche ich das so:

    class EventData {
    private:
      Time time;
    public:
      EventData(Time time) : time(time) {}
      virtual ~EventData() {}
      Time getTime() const { return time; }
    };
    class JoinEventData : publuc EventData {
    private:
      Channel chan;
    public:
      JoinEventData(Time time, Channel const& chan) : EventData(time), chan(chan) {}
      Channel const& getChannel() const { return channel; }
    };
    

    und dann mache ich in Session::join folgendes:

    fireEvent(Event(EventType::JOIN, new JoinEventData(getTime(), channel));
    

    PS:
    und im Client Code dann:

    session.registerEventListener(EventType::JOIN, ([&](Event evt) {
      JoinEventData const* data=static_cast<JoinEventData const*>(evt.getData());
      cout<<"Joined Channel: "<<data.getChannel();
    }));
    


  • Das haette dann aber den Nachteil, dass Client-Code explizit auf den richtigen Eventtyp casten muss. Evtl. koennte ich dann einfach addEventListener zu einem template machen, dass eine Trampolinfunktion verwendet, um auf den richtigen Typ zu casten.



  • Kellerautomat schrieb:

    Das haette dann aber den Nachteil, dass Client-Code explizit auf den richtigen Eventtyp casten muss. Evtl. koennte ich dann einfach addEventListener zu einem template machen, dass eine Trampolinfunktion verwendet, um auf den richtigen Typ zu casten.

    Finde ich nicht so toll.

    Du könntest EventData einfach so definieren, dass es immer die selben Felder sind. Ist halt unflexibler, aber du könntest sagen, jedes event hat eben einen channel, eine uhrzeit, einen sender, etc.

    Ich finde das mit dem casten ganz angenehm - da du plötzlich komplett frei bist, was die events betrifft. Session muss nichts wissen. Und in vielen Event Listener braucht man die Event Daten ja auch garnicht. Wenn du das Casten nicht willst, mach mit einer Umwandlungs Funktion die das Casten übernimmt.

    zB könnte getData eine Template Funktion sein:

    JoinEventData const* data=evt.getData<JoinEventData>();
    

    Oder getData liefert ein Proxy Objekt dass einen template operator T* für den Cast hat.

    Das coole an dem System ist eben:
    Du kannst jederzeit neue Events hinzufügen ohne Code ändern zu müssen. Und vorallem: du kannst User Events erlauben.

    Ich kann zB ein Plugin schreiben dass bei jeder Nachricht in einem Channel auf meinen Namen hört und wenn mein Name vorkommt dann feure ich ein Event MyNameWasMentioned ab.

    Fixe Events vorauszusetzen ist unflexibel.



  • Die Events werden doch von session erzeugt und verteilt? Wie soll ich da User-Events erlauben?



  • Kellerautomat schrieb:

    Die Events werden doch von session erzeugt und verteilt? Wie soll ich da User-Events erlauben?

    Ich dachte du wolltest das entkoppeln?

    Session muss dann ja alles checken und überwachen. Ich würde zB Session nur ganz wenige Events anbieten lassen. zB MessageReceived. Und darauf hören dann viele Listener. zB einer der Joins von anderern Usern abfängt und dann eben ein UserJoined Event triggert.

    Wenn Session selber alles handeln soll, dann ist es ein gott objekt 😉

    Aber es reicht eine minimale Funktionalität anzubieten - wie eben MessageReceived und vielleicht ActionReceived und der Rest wird von Listenern gemacht.

    So kannst du ohne Probleme dann so sachen wie einen bad-word filter einbauen, etc.



  • Wollte ich auch, aber dafuer habe ich bisher keine Idee...



  • Kellerautomat schrieb:

    Wollte ich auch, aber dafuer habe ich bisher keine Idee...

    Ansonsten schau dir einfach GUI Frameworks an - die haben alle genau diese Problematik (nur etwas komplexer) und lösen sie auf gewisse Weise.



  • Shade Of Mine schrieb:

    //Client Code wäre dann:
    session.addEventListener(Event.CONNECT, ([&](irc::event const& e) { session.join("#f00"); }));
    session.addEventListener(Event.JOIN,
         [&] (irc::event const& e) 
         { 
             if(e.user().nickname != session_data.nickname) 
                 session.message(e.channel(), "Welcome " + e.user().nickname + " to " + e.channel() + "!"); 
         } 
    );
    

    Was macht das "[&]"? ich seh das zum ersten mal




Anmelden zum Antworten