Wiedermal eine Designfrage
-
Hallo,
Tut mir leid dass ich schon wieder von so einem Thema anfange aber die Threads die ich hierzu gefunden habe, haben mir leider nicht wirklich weiter geholfen.
Also ich versuche euch mal mein Problem zu schildern.Ich Programmiere zur Zeit eine Oberfläche die ein sogenanntes TabWidget, also einen Karteireiter enthält. In diesen Tabwidget können verschieden Tabs geöffnet werden. Jedes einzelne dieser Tabs besitzt ein Flag das besagt, ob die Daten schon gespeichert wurden oder nicht. Das Design sieht demnach vereinfacht dargestellt so aus:
class clientTab { public: clientTab(); bool isSaved(); bool save(); ... private: saved; ... };In der Methode isSaved() wird überprüft ob der Inhalt des Tabs gespeichert wurde. Wenn nicht, wird der Benutzer gefragt ob er dies tun möchte.
Soviel zu der Vorgeschichte.
Mittlerweile existieren in dem Programm 7 verschieden Tabs. Bei den vom Benutzer durchgeführten Aktionen, z.B. Tab schließen, neuen Tab öffnen usw. soll der Speicherstatus des aktuell angezeigte Tabs mittels der oben beschriebenen Funktion überprüft werden. Ich finde das zeugt nicht gerade von einer schicken Programmierung wenn man bedenkt, dass egal bei welcher aktion, überprüft werden muss, welcher tab gerade angezeigt wird und ob dieser schon gespeichert ist.
Aus diesem Grund habe ich mir überlegt eine Klasse tab zu schreiben von der alle anderen tabs abgeleitet sind. Die Methoden isSaved() und save() würde ich dann als virtuell deklarieren, da jede abgeleitete Klasse anders reagieren, zum Beispiel eine andere Meldung ausgeben soll. Bis jetzt is das noch alles ganz einleuchtend, nehme ich an?!
Jetzt zu meiner Frage:
Manche Tabs besitzen z.B. die methoden lock() (zum Sperren der Eingabefelder) und unlock() (zum Entsperren versteht sich
) Diese Methoden werden aber nicht von jeder abgeleiteten Klasse benötigt was ja letzenendes bedeutet, dass es nicht sinnvoll wäre, diese virtuell zu sondern in der jeweiligen Klasse zu deklarieren. Wenn ich dies aber tue tritt das Problem auf dass ich jedesmal ein static_cast durchführen muss, um auf die entsprechenden Methoden zuzugreifen, was wiederrum nicht gerade für eine saubere Programmierung spricht.
Ich hoffe ich konnte euch wenigsten ein wenig nahe bringen wo mein Problem liegt und vllt könnt ihr mir ja ein paar tips geben.Schonmal vielen Dank im Voraus
SaschaEDIT: Ich habe diese Frage extra hierein gestellt da es sich sogesehen nicht um ein Problem bei der Oberflächenprogrammierung sondern der Vererbung, also reines c++ handelt.
-
Wie dynamisch ist denn die Anwendung aufgebaut? Wenn mehrere stark unterschiedliche Tabs in einer festen Anordnung zusammengestellt sind, kannst du jeden als eigenständige Variable verwenden und ersparst dir unnötige Cast's:
class TabWidget { clientTab m_client; serverTab m_server; ... baseTab* m_active;//baseTab ist die gemeinsame Basisklasse von clientTab, serverTab etc };Methoden, die für alle (oder die meisten) Tab-Klassen nötig sind, legst du in der Basisklasse an (notfalls mit einer NoOp-Defaultimplementation), andere Methoden (z.B. Getter auf die jeweiligen Eingabedaten) sind spezifisch in den einzelnen Klassen und werden direkt über m_client etc verwendet.
(eventuell kann sich die Klasse zusätzlich selber merken, ob sie gerade aktiv ist)
-
Vielen Dank für die schnelle Antwort.
Also zur Zeit existieren die Klassen clientTab (Beinhalten Kundeninformationen) userTab (Beinhalten Informationen zum Benutzer eines Kunden), billingTab (zur Abrechnung) und andere. Es können mehrere Benutzer als auch Kunden geöffnet werden. Demnach kann man nicht unbedingt von einer festen Anordung ausgehen.Methoden, die für alle (oder die meisten) Tab-Klassen nötig sind, legst du in der Basisklasse an (notfalls mit einer NoOp-Defaultimplementation)
Tut mir leid aber ich versteh nicht ganz wie du das meinst. Kannst du mir das genauer erklären?
-
Hoschek schrieb:
Vielen Dank für die schnelle Antwort.
Also zur Zeit existieren die Klassen clientTab (Beinhalten Kundeninformationen) userTab (Beinhalten Informationen zum Benutzer eines Kunden), billingTab (zur Abrechnung) und andere. Es können mehrere Benutzer als auch Kunden geöffnet werden. Demnach kann man nicht unbedingt von einer festen Anordung ausgehen.Hm, dann kannst du die einzelnen Tab-Typen auch in vector<>en unterbringen (über die bekommst du auch eine Zuordnung zum "dritten Kunden" oder "fünften Benutzer").
Methoden, die für alle (oder die meisten) Tab-Klassen nötig sind, legst du in der Basisklasse an (notfalls mit einer NoOp-Defaultimplementation)
Tut mir leid aber ich versteh nicht ganz wie du das meinst. Kannst du mir das genauer erklären?
Das bedeutet, daß eine fast überall benötigte Methode in der Basisklasse mit leerem Rumpf definiert und bei Bedarf von den Kindklassen überschrieben wird (wenn ein Tab keine Eingabefelder hat, die gesperrt werden müssen, machen lock() und unlock() auch gar nichts).