Klassen Design für persistente Config



  • Hallo zusammen,

    ich habe eine recht einfache Config Klasse geschrieben, welche diverse Attribute als Member hat und in eine Datei geschrieben und gelesen werden kann.

    Ein konkretes Beispiel ist meine Klasse Webservice, welche Requests zu einem Server macht. Die hatte bisher einen Member "baseUrl" und hat damit entsprechend die Requests gemacht.
    Jetzt will ich aber das die baseUrl konfigurierbar ist und im besten Fall eben ohne Neustart der Applikation.

    Daher die Frage: Wie kommt die Webservice Klasse an die aktuelle baseUrl?

    Die aktuelle Realisierung sieht wie folgt aus:

    • Meine Application Klasse, die so als Einstieg in die Applikation dient, erzeugt eine Instanz der Config Klasse (shared_ptr)
    • Die Config shared ptr instanz wird dann entsprechend runter gegeben in alle Klassen z.B. Webservice, die eben Zugriff auf Daten der Config benötigen
    • Jede Klasse speichert sich die Config ab und liest eben dann immer die Daten raus, die es braucht

    Das funktioniert, aber ich bin irgendwie etwas unzufrieden damit. Was mich primär daran stört ist das Gefühl, dass es mein Klassen Design / OOP Design einfach kaputt macht.

    1. Die Klassen haben plötzlich auf alles Zugriff. Weil die Config Klasse enthält im Zweifelsfall ja alle Konfig Werte und eben nicht nur die baseUrl, die jetzt hier benötigt wird. Das erhöht irgendwie die Kopplung.
    2. Die einigermaßen wohlüberlegten Attribute des Objektes werden plötzlich durch ein "Config" Objekt ersetzt

    Insbesondere Punkt 2 macht mir da etwas zu schaffen. Ich stelle mir da die Spielzeug Beispiele aus Büchern, Uni etc. vor, wo man lernt Objekte haben Verhalten und Attribute und an die echte Welt angelehnt etc.
    Und dann möchte man das plötzlich konfigurierbar haben und schmeißt alle seine Attribute weg und packt stattdessen so ein Config Objekt da rein 😃

    (Oder nutzt ein Singelton und hat dann gar keine Attribute mehr und noch viel mehr Spagetthi Code)

    Übertreibe ich? Oder ist meine bisherige Lösung tatsächlich aus Design Perspektive beschissen? Wie geht es besser?



  • Eine Config Klasse, die von außen irgendwo geändert werden kann und dann das Verhalten einer anderen Klasse verändert, finde ich unschön.
    Ich mache es auch schon mal, dass ich, wenn ich mehrere Werte an eine Klasse weiter geben will, die in ein Strukt oder so packe. Dann bekommt die Klasse aber nur dieses Strukt und speichert sich eine Kopie davon.

    Wenn du zur Laufzeit was ändern möchtest, kannst du doch einfach einen Setter für die URL schreiben und den aufrufen, wenn sich was geändert hat, oder?



  • Ja, da sprichst du evtl. auch noch ein drittes Problem an, was mir so durch den Kopf gegangen ist.

    Die Begründung für die Config Klasse an sich ist jetzt primär, weil das ganze halt als Datei abgelegt wird. Das ist quasi dann die Repräsentation als Objekt davon.

    Den Gedanken mit dem setter hatte ich auch, dass das das sauberste irgendwie wäre. Ich war mir jetzt nur doch etwas unsicher wie konkret die Realisierung aussieht.

    Meine Sorge war hier nur etwas, dass das schnell recht kompliziert wird. Weil man die Änderungen, die an Stelle A passieren irgendwie dort dann auch hinbringen muss, dass der setter aufgerufen wird.
    Ich glaube aktuell stellt das noch kein Problem dar, aber das war zumindest mein Gedanke, dass es in Zukunft nicht so skalieren könnte.
    Da wären vlt. dann Signal / Slots praktisch. Aber Qt wollte ich auf dieser Ebene eig. nicht haben.



  • Ich würde versuchen jene Klassen die nicht stark mit der Applikation verwoben sein müssen auch unabhängig zu halten. D.h. die bekommen keine "alles in einem" Config Klasse und eher auch keine Signals/Slots.

    Die Config-Klasse zum halten der Daten aus dem Config-File kannst du ja trotzdem machen. Macht auch Sinn, z.B. um Dinge wie nen Config-Dialog vom Code zum Laden/Speichern der Settings zu entkoppeln.

    Diese Config-Klasse kannst du dann verwenden um die Config zu laden. Und dann schaufelst du die Werte halt in Objekte von anderen, spezifischen Config-Klasse um, übergibst sie im Konstruktor oder setzt sie mit Settern in die Objekte der unabhängigen Klassen rein.

    In der Applikation selbst kannst du dann auch ruhig mit Signals/Slots arbeiten um Änderungen zu verteilen. Oft ist es aber auch völlig ausreichend vor jeder verwendung eines Objekts den Setter aufzurufen. z.B. eine URL zu setzen obwohl sie sich vermutlich gar nicht geändert hat ist nicht wirklich so teuer dass man es vermeiden müsste.

    Der Vorteil wenn du es so machst ist die bessere Kapselung, und die wirkst sich mehrfach positiv aus:

    • Der Code wird dadurch einfacher zu verstehen, weil du die unabhängigen Klassen isoliert betrachten kannst.
    • Es wird einfacher Unit-Tests bzw. allgemein automatisierte Tests zu schreiben.
    • Der explizite Code zum Daten umschaufeln macht sichtbar wann/wie/wo Daten von A nach B fliessen.
    • Das Risiko mit inkonsistenten Daten zu arbeiten wird viel geringer (z.B. neues Setting für URL aber noch alte Credentials/Zertifikate etc.)

    ps: Man kann ganz allgemein sagen dass saubere Trennung/Entkoppelung so-gut-wie immer mit dem manuellem Umschaufeln von Daten einhergeht. Den Umstand dass man an etlichen Stellen etliche Werte von A nach B umschaufeln muss sollte man also nicht als Schwachstelle ansehen. Denn sobald man versucht diese Schwachstelle zu beheben, fängt man sich damit stärkere Koppelung zwischen A und B ein.


Anmelden zum Antworten