Konzept für Zugriff auf Einstellungen



  • Hallo!

    Ich beabsichtige ein größeres Programm zu schreiben, das eine Menge Einstellungen zu speichern hat. Jetzt stellt sich die Frage, wie ein gutes Konzept für den Zugriff auf diese Einstellungen aus dem Quellcode heraus aussieht.

    Ich denke z.B. an eine Klasse, die die einzelnen Einstellungen als Eigenschaften anbietet; evtl. sogar als BCB-mäßige __property mit {read=, write=}-Handler, der dann das eigentliche Auslesen/Speichern macht. Nur ist es dann natürlich sehr aufwendig, für jeden zu speichernden Wert einen eigenen Lese- und einen Schreibhandler zu schreiben.

    Was könnte man denn noch machen, was nachher einfach zu erweitern und komfortabel zu benutzen ist?



  • Die Idee mit den gettern/settern klingt schlüssig, aber Du wirst damit niemals glücklich werden. Wir hatten das hier in einem Projekt auch so gelöst, aber das schafft eine ewige Pflegebaustelle. Vor allem bei vielen Einstellungen willst/mußt Du diese ja in einer Datei am Ende abspeichern, dann mußt Du für jede Einstellungen eine Property erzeugen und daran denken, diese zu sichern.

    Sinnvoller ist es einen Container zu schreiben, der Eigenschaften über ein Token abrufbar macht. Vor allem wird die Speicherung trivial, da es sich nur noch um eine Schleife über alle Tokens handelt.

    Das sieht dann so aus:

    PropContainer props;
    props.SetValue("initialval", "mr. time");
    if (props.GetValue("initialval") == "mr. time")
    {
    }
    

    Für die Tokens Strings zu verwenden ist naheliegend, aber muß man noch mal unter Timinggesichtspunkten prüfen. Eine Map als interne Struktur liegt nahe, noch näher wohl eine Hashmap. Dann kannst Du noch eine Funktion erstellen, die für ein Token eine Hash-ID erzeugt... etwa so:

    class Something
    {
    public:
       Something()
          : m_HashInitvalue(props.GetHashForToken("Initvalue"))
       {};
    private:
       void func()
       {
          if (props.GetValue(m_HashInitvalue) == "...")
          {
          }
       }
       int m_HashInitvalue;
    };
    

    Damit erspart man sich die Stringvergleiche.

    ---Extension:

    Eventuell mußt Du noch mal die Dateien für die Properties untergliedern, also vielleicht nach Themen "GUI", "Sensor", "Konfiguration", etc. Dann hast Du eigene Property-Objekte pro Thema. Das entspricht quasi der Überschrift in den ini-Dateien ("[Thema]") oder auch einem Dateinamen.

    Damit bekommst Du dann noch mal eine weitere Gliederungsebene, so daß Du praktisch so vorgehen würdest:

    Properties props;
    PropertyGroup* propgroup;
    
    propgroup = props.GetNode("GUI");
    int i = propgroup->GetValue("Minimized");
    

    Properties sollte in diesem Fall ein Singleton sein, das wäre der Aufgabe angemessen. Und dann noch die Sache mit dem Stringverzicht/Hashing. 😉

    Solltest Du aber nur viele Werte haben und diese nicht allzu oft schreiben/lesen, kannst Du mit den Strings wohl sogar leben. Aber immer als const Ref& übergeben.



  • Wow! Danke!

    Das muss ich erst einmal verdauen. 😉



  • So, ich habe jetzt mal eine Testklasse erstellt, die intern mit einer std::map arbeitet. Funktioniert auch alles sehr schön.
    Ich habe aber noch 2 Fragen:

    1. Die einzelnen Wertebezeichner (Token) müsste ich immer als String direkt in den Quellcode eingeben; also entweder bei .GetValue() oder bei .GetHashForToken(). Ich sehe hier die Gefahr, dass man sich vertippt und dann den falschen Wert geliefert bekommt oder auch 2 mal das gleiche unter jeweils einem anderen Namen gespeichert wird (.SetValue()).
    Ich hätte gerne, dass man alle möglichen Token beim Programmieren vom Editor zur Auswahl angezeigt bekommt, d.h. beim BCB oder VC++ klappt ja nach dem Drücken von . oder -> eine Liste herunter. Man könnte also alle möglichen String-Token als Konstanten in der Klasse PropContainer definieren und hätte sie beim Programmieren zur Auswahl.
    Was sagst du/sagt ihr dazu?

    2. Wenn ich eine Hashmap nehme, dann generiert mir ja die Methode GetHashForToken() aus einem String eine mehr oder weniger eindeutige Zahl. Dabei kann mir doch niemand sicherstellen, dass nicht 2 Token den gleichen Hash bekommen, oder?



  • Meine Einstellungen speichere ich so ähnlich wie von Marcus vorgeschlagen. Lediglich auf das [Thema] habe ich verzichtet, ich mache das mit so einer Art "Verzeichnis", indem ich zusammengehörige Einstellungen zusammenfasse (als Teil des Strings):

    "GUI/MainWindow/Position"
    "GUI/DBFImport/Position"
    "GUI/DBFImport/Path"
    "GUI/DBFImport/Codepage"
    "Database/DNS"

    usw...

    So ist's immernoch ein Simpler String, aber trotzdem einigermassen Geordnet.

    Ich selbst benutze eine Map, weil Hash-Map (noch) nicht zu Standard C++ gehört.

    Wenn du eine Hash-Map verwendest ist in der Tat nicht sichergestellt, das nicht zwei Schlüssel denselben Hash-Wert erhalten. Aber um diese Konflikte kümmert sich eigentlich die Hash-Map nicht du.

    Was das Anzeigen aller möglichen Tokens angeht: Wenn du das willst, bist du wieder genau bei der von Marcus angesprochenen Ewigen Baustelle. Du könntest z.B. ganz simpel alle Einträge deines Containers mit Default-Werten vorbelegen und eine Funktion zur Verfügung stellen um diese Abzufragen. So könntest du auch gleich eine Exception werfen, wenn jemand versucht einen Wert abzufragen oder zu setzen, der nicht vorgesehen ist. So musst du aber bei jedem neuen Token deine Klasse anpassen.



  • Das mit der Liste hat frenki ja angesprochen, um zu verhindern daß jemand nach fehlenden Tokens sucht, wirf eine Exception. Oder schreib derartige Fehlzugriffe in eine Datei, die Du auswertest. Dann bekommst Du das nach einem Programmlauf raus.

    Das mit der ID ist zwar richtig, verschiedene Strings können die gleiche ID haben. Aber eine richtig implementierte Hash-Verwaltung liefert in diesem Falle dann trotzdem eine eindeutige ID.



  • Ok, ich bin überzeugt und werde meine Container-Klasse nicht als ewige Baustelle aufbauen.

    Und jetzt die Frage, auf die alle schon gewartet haben:

    Gibt es irgendwo eine gute/richtige Hashmap, die ich verwenden könnte?



  • In der Boost-Lib. Vor allem ist boost sowas wie die inoffizielle Erweiterung der stdlib, d.h. Du bewegst Dich damit verdammt nahe an einem Quasi-Standard.



  • Sicher? Ich sehe da keine Hash-Map 😞
    http://www.boost.org/libs/libraries.htm

    Oder wo ist die aufgeführt?




Anmelden zum Antworten