Frage

Ich habe ein Programm, das (unter anderem) eine Befehlszeilenschnittstelle hat, die der Benutzer eingeben Strings kann, die dann über das Netzwerk gesendet werden. Das Problem ist, dass ich nicht sicher bin, wie die Ereignisse zu verbinden, die tief in der GUI erzeugt werden, an die Netzwerk-Schnittstelle. Nehmen wir zum Beispiel, dass meine GUI Klassenhierarchie wie folgt aussieht:

GUI -> Mainwindow -> Command -> EntryField

Jedes GUI-Objekt enthält einige andere GUI-Objekte und alles ist privat. Nun ist das entryField Objekt erzeugt eine Ereignis / Signal, dass eine Nachricht eingegeben wurde. Im Moment bin ich vorbei das Signal auf der Klassenhierarchie, so dass die CLI-Klasse wie folgt aussehen würde:

public:
    sig::csignal<void, string> msgEntered;

Und im c'tor:

entryField.msgEntered.connect(sigc::mem_fun(this, &CLI::passUp));

Die passUp Funktion sendet nur das Signal wieder für die besitzende Klasse (Mainwindow) zu verbinden, bis ich dies in der Hauptschleife schließlich tun können:

gui.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));

Nun scheint dies wie eine echte schlechte Lösung. Jedes Mal, wenn ich etwas hinzufügen, auf die GUI Ich habe es durch die Klassenhierarchie verkabeln. Ich mache mehrere Möglichkeiten, um dies zu sehen. Ich konnte machen alle Objekte der Öffentlichkeit, die mir erlauben würde, gerade dies zu tun in der Hauptschleife:

gui.mainWindow.cli.entryField.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));

Aber das gegen die Idee der Kapselung gehen würde. Ich könnte auch einen Verweis auf die Netzwerk-Schnittstelle auf der ganzen GUI passieren, aber ich möchte den GUI-Code als separate wie möglich halten.

Es fühlt sich an wie ich hier etwas Wesentliches fehlt bin. Gibt es eine saubere Art und Weise, dies zu tun?

Hinweis: Ich bin mit GTK + / gtkmm / libsigc ++, aber ich bin es nicht als solches Tagging, weil ich so ziemlich das gleiche Problem mit Qt hatte. Es ist wirklich eine allgemeine Frage.

War es hilfreich?

Lösung

Kurz einige globale Pub / Sub-Nabe, gehen Sie nicht weg von etwas nach oben oder unten in der Hierarchie übergeben. Auch wenn Sie abstrakt die Zuhörer auf eine generische Schnittstelle oder einen Controller, haben Sie immer noch irgendwie den Controller an den UI-Ereignis zu befestigen.

Mit einem Pub / Sub-Hub Sie eine weitere Schicht der Dereferenzierung hinzufügen, aber es gibt noch eine Verdoppelung - die entryField sagt noch ‚veröffentlichen Nachricht bereit Ereignis‘ und der Hörer / Controller / Netzwerk-Schnittstelle sagt ‚für die Nachrichten bereit Ereignis hören‘, so gibt es eine gemeinsame, die Ereignis-ID beiden Seiten darüber wissen müssen, und wenn du gehst nicht zu hart Code, der dann an zwei Stellen muss es (wenn auch als global in beiden Dateien weitergegeben werden sie nicht als Argument übergeben wird, die in selbst ist nicht großer Vorteil).

Ich habe alle vier Ansätze - direkte Kopplung, Controller, Hörer und Pub-Sub - und in jedem Nachfolger Sie die Kupplung etwas lockern, aber Sie jemals aus, die einige Überschneidungen nicht weg, auch wenn es nur die ID des veröffentlichten Ereignisses.

Es kommt wirklich auf Varianz. Wenn Sie Sie in einer anderen Implementierung der Schnittstelle wechseln finden müssen, abstrahiert dann die konkrete Schnittstelle als Controller lohnt. Wenn Sie Sie andere Logik haben, finden müssen, den Zustand zu beobachten, ändern Sie es für einen Beobachter. Wenn Sie es zwischen Prozessen entkoppeln müssen, oder in eine allgemeine Architektur stopfen wollen, pub / sub kann funktionieren, aber es stellt eine Form der globalen Zustand, und ist nicht so zugänglich zu kompilieren Zeit zu überprüfen.

Aber wenn Sie es sind die Teile des Systems variieren müssen nicht alleine wahrscheinlich nicht der Mühe wert.

Andere Tipps

Das eigentliche Problem ist, dass Sie die GUI wie seine eine monolithische Anwendung sind zu behandeln, nur die gui auf den Rest der Logik über einen größeren Draht als üblich verbunden ist.

Sie müssen neu denken, wie die GUI mit dem Back-End-Server interagiert. Im Allgemeinen bedeutet dies, Ihre GUI eine eigenständige Anwendung wird , das tut so gut wie nichts und spricht mit dem Server ohne direkte Kopplung zwischen den Interna der GUI (dh Ihrer Signale und Ereignisse) und die Verarbeitungslogik des Servers. das heißt, wenn Sie auf eine Schaltfläche klicken Sie kann es eine Aktion durchzuführen, in diesem Fall müssen Sie den Server anrufen, aber fast alle anderen Ereignisse müssen nur den Zustand ändern in der GUI und nichts tun, um den Server - erst Sie sind bereit, oder der Benutzer eine Antwort hinterlassen, oder Sie haben genügend Leerlaufzeit, die Anrufe im Hintergrund zu machen.

Der Trick ist, eine Schnittstelle für den Server völlig unabhängig von der GUI zu definieren. Sie sollten GUIs der Lage sein, später zu ändern, ohne überhaupt den Server zu ändern.

Das heißt, dass Sie nicht in der Lage sein, die Ereignisse automatisch gesendet haben, werden Sie sie manuell verdrahten müssen auf.

Versuchen Sie, die Observer Design-Muster. Link enthält Beispielcode ab sofort.

Das Wesentliche, was Sie fehlt, ist, dass Sie einen Verweis ohne Verletzung Verkapselung passieren kann, wenn die Referenz als eine Schnittstelle (abstrakte Klasse), die gegossen wird Ihr Objekt implementiert.

Da dies eine allgemeine Frage ist, werde ich versuchen, es selbst zu beantworten, obwohl ich „nur“ ein Java-Programmierer. :)

Ich ziehe Schnittstellen (abstrakte Klassen oder was auch immer der entsprechende Mechanismus in C ++) verwenden, um auf beiden Seiten meiner Programme. Auf der einen Seite gibt es das Programm Kern, der die Geschäftslogik enthält. Es können Ereignisse erzeugen, die beispielsweise GUI-Klassen können erhalten, zum Beispiel (Für Beispiel) „stringReceived.“ Der Kern auf der anderen Seite implementiert einen „UI-Listener“ Schnittstelle, die Methoden wie „stringEntered“ enthält.

Auf diese Weise die Benutzeroberfläche vollständig von der Business-Logik entkoppelt. Durch die entsprechenden Schnittstellen implementieren, können Sie sogar eine Netzwerkschicht zwischen Kern und der Benutzeroberfläche vor.

[Bearbeiten] In der Starterklasse für meine Anwendungen ist es fast immer diese Art von Code:

Core core = new Core(); /* Core implements GUIListener */
GUI gui = new GUI(); /* GUI implements CoreListener */
core.addCoreListener(gui);
gui.addGUIListener(core);

[/ Edit]

Meiner Meinung nach sollte die CLI unabhängig vom GUI sein. In einer MVC-Architektur, sollte es die Rolle des Modells spielen.

Ich möchte einen Controller setzen, die sowohl EntryField und CLI verwaltet. Jedes Mal EntryField Änderungen, CLI invoqued wird, all dies von der Steuerung verwaltet wird

Sie können ANY GUI entkoppeln und kommunizieren einfach mit Nachrichten über templatious virtuelles Pack . Schauen Sie sich dieses Projekt auch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top