2009-07-08 11 views
7

Hier eine einfache Aufgabe: Konfigurationseinstellungen aus einer Konfigurationsdatei lesen, die Einstellungen (zB als Hash) in einem Objekt speichern, auf dieses Objekt von verschiedenen Objekten zugreifen, die auf die Konfiguration zugreifen müssen Parameter.So erstellen Sie ein globales Parameterobjekt

Ich fand this implementation für die ConfigFile-Klassenimplementierung und es funktioniert. Meine Frage ist: Was ist der beste Weg, um eine Instanz dieser Klasse von meinen anderen Klassen zur Verfügung zu stellen und threadsicher zu sein, vermeiden Sie statische Faile der statischen Reihenfolge, etc.

Mein aktueller Ansatz ist, es in main() mit zu konstruieren

// Read face detection related parameter values from the configuration file. 
string configFileName = "detection_parameters.txt"; 
try { 
    parameters = ConfigFile(configFileName); 
} 
catch(ConfigFile::file_not_found) { 
    cerr << "configuration file not found: " << configFileName << endl; 
    exit(-1); 
} 

und dann Parameter eine globale Variable machen. Aber ich lese auch, dass Singletons anstelle von globalen Variablen verwendet werden sollten. Wie kann das Singleton mit dem Dateinamen instanziiert werden?

Das muss so eine gemeinsame Aufgabe sein, dass ich denke, dass es eine allgemein akzeptierte gute Methode dafür geben muss? Ich würde mich freuen, wenn mir jemand darauf hinweisen könnte.

Danke, C

Antwort

6

Wenn Sie selbst rollen wollen, würde ich empfehlen, das Singleton-Entwurfsmuster für Ihre Konfigurationsklasse zu verwenden. Lassen Sie die Klasse selbst einen statischen Zeiger ihres eigenen Typs speichern, und der Konstruktor ist privat, sodass man gezwungen wäre, den statischen Getter zu verwenden, um die eine Instanz der Klasse zu erhalten.

so ein Mock-up (das nicht kompiliert werden kann, ein Spaß Config Funktionalität fehlt, soll aber den Punkt zeigen)

class Config 
{ 
public: 
    static Config * getConfig(); 
    static void setConfigFileName(string filename); 
private: 
    Config(); 
    static string m_filename; 
    static Config * m_configInstance; 
}; 

Falls ich nicht klar zu sein, die getConfig() würde schau dir m_configInstance an. Wenn es kein gültiges ist, dann würde es eines erstellen (hat Zugriff auf den privaten Konstruktor) und es in m_configInstance speichern, so dass jeder nachfolgende Aufruf auf dasselbe zugreifen würde.

Also würde Ihr main() setConfigFileName() verwenden, dann müsste jede Klasse Config :: getConfig() aufrufen und dann die Operationen aufrufen. Viel sauberer als eine globale Standardvariable.

Explosion - in der Zeit, die ich verbrachte, dies zu schreiben, haben andere Leute das Singleton Design-Muster auch vorgeschlagen. Ah gut - hoffe die zusätzliche Erklärung hilft.

2

Haben Sie bei Boost's Program Options Bibliothek geschaut?

+0

Die Boost PO Bibliothek behandelt Kommandozeilenprogramm Optionen, meine Frage war über Konfigurationsoptionen aus einer Datei gelesen werden. – recipriversexclusion

+0

Sie können aus einer Konfigurationsdatei mit dieser Bibliothek lesen. –

2

Was ich für meine Konfigurationsklasse getan habe, ist eine statische Singleton-Klasse mit einem Hashtable-Cache zu erstellen. Meine Konfigurationsdatei wurde zum Lesen und Schreiben entwickelt, um die Anwendungseinstellungen zu ändern.

Immer wenn ein Aufruf ausgeführt wird, um eine Einstellung zu ziehen, führe ich eine Suche auf der Hashtabelle durch, wenn es nicht dort ist, dann lese ich die Einstellung aus der Datei, sperre die Hashtabelle und lege sie in die Hashtabelle. Die Hashtabelle ist sehr schnell für Lookups.

0

Ich stimme Chris, verwenden Sie ein Singleton. Das Schöne an dem Singleton-Muster ist, dass es nur die Daten initialisiert/sammelt, die Sie benötigen, wenn Sie das erste Mal versuchen, darauf zuzugreifen, von da an ist es für jeden verfügbar, der daran interessiert ist. Wenn Sie die Konfiguration ändern möchten, müssen Sie den Writer sperren.

2

Mit der Erwähnung der "statischen Initialisierung Reihenfolge Fiasko", nehme ich an, dass Sie Konfigurationselemente verfügbar haben müssen, um einige statische Objekte zu initialisieren. Eine Singleton-ConfigFile-Klasse funktioniert, aber Sie müssen die Art ändern, wie Sie den Dateinamen abrufen, da die Informationen vor dem Start von main() benötigt werden. Sie benötigen ein anderes Singleton, um den Dateinamen anzugeben, oder erstellen Sie den Dateinamen in der Konfigurationsklasse selbst.

0

Ich habe eine Technik ähnlich dem Singleton-Entwurfsmuster verwendet, um globale Ressourcen wie diese zu konfigurieren.

class Config 
{ 
public: 
    Config(const string & filename) { 
     if (m_configInstance) { 
     throw AlreadyInitException; 
     } 
     // do main init 
     m_configInstance = this; 
    } 

    ~Config() { 
     m_configInstance = 0; 
    } 

    static Config * getConfig() { 
     if (!m_configInstance) { 
     throw NoConfigException; 
     } 
     return m_configInstance; 
    } 

private: 
    static Config * m_configInstance; 
}; 

Config * Config * m_configInstance = 0; 

Die Konstruktor Tests, dass m_configInstance nicht gesetzt ist, wenn sie es löst eine Ausnahme ist. Dann beendet es die Konstruktion und registriert sich selbst, indem m_configInstance auf this gesetzt wird.

Die Methode getConfig gibt die Instanz oder die Würfe und die Ausnahme zurück, wenn sie nicht festgelegt ist.

Der Destruktor setzt die m_configInstance wieder auf 0.

Um die Klasse zu verwenden, konstruiere sie einmal am Anfang von main(). Dann greifen Sie darauf zu, wenn die Methode getConfig() dies erfordert.

Jetzt wird die Lebensdauer des Objekts Config im Gegensatz zu einem Singleton sauber gesteuert. Und das hat einen zusätzlichen Vorteil für Komponententests, jeder Test oder jede Testsuite kann dort ein eigenes Config Objekt erstellen, und alle sind zwischen den Tests sauber aufgeräumt.