2008-08-15 7 views
2

Eine Datenbankanwendung, an der ich gerade arbeite, speichert alle Arten von Einstellungen in der Datenbank. Die meisten dieser Einstellungen dienen dazu, bestimmte Geschäftsregeln anzupassen, aber es gibt auch andere Dinge.Zugriff auf globale Anwendungseinstellungen

Die App enthält Objekte, die speziell eine bestimmte Aufgabe ausführen, z. B. eine bestimmte komplizierte Berechnung. Diese Nicht-UI-Objekte sind Unit-getestet, benötigen aber auch Zugriff auf viele dieser globalen Einstellungen. Die Art, wie wir dies jetzt implementiert haben, besteht darin, den Objekten Eigenschaften zu geben, die zur Laufzeit vom Application Controller gefüllt werden. Beim Testen erstellen wir die Objekte im Test und geben Werte zum Testen ein (nicht aus der Datenbank).

Das funktioniert besser, auf jeden Fall viel besser als alle, die diese Objekte Einstellungen Objekt eine globale brauchen --- das macht natürlich effektiv Unit-Tests unmöglich :) Nachteil sein können, dass Sie manchmal ein Dutzend festlegen müssen Eigenschaften, oder Sie müssen diese Eigenschaften in Unterobjekte "perkolieren" lassen.

Also die allgemeine Frage ist: Wie bieten Sie Zugriff auf globale Anwendungseinstellungen in Ihren Projekten, ohne die Notwendigkeit für globale Variablen, während immer noch in der Lage, Einheitscode testen? Dies muss ein Problem sein, das 100-mal gelöst wurde ...

(Anmerkung: Ich bin kein allzu erfahrener Programmierer, wie Sie bemerkt haben; aber ich liebe es zu lernen! Und natürlich, ich habe bereits Forschung zu diesem Thema, aber ich bin wirklich auf der Suche nach Erfahrungen aus erster Hand)

Antwort

1

Sie könnten Martin Fowlers ServiceLocator Muster verwenden. In PHP könnte es so aussehen:

class ServiceLocator { 
    private static $soleInstance; 
    private $globalSettings; 

    public static function load($locator) { 
    self::$soleInstance = $locator; 
    } 

    public static function globalSettings() { 
    if (!isset(self::$soleInstance->globalSettings)) { 
     self::$soleInstance->setGlobalSettings(new GlobalSettings()); 
    } 
    return self::$soleInstance->globalSettings; 
    } 
} 

Ihre Produktion Code initialisiert dann den Dienst-Locator wie folgt aus:

ServiceLocator::load(new ServiceLocator()); 

In Ihrem Test-Code, können Sie Ihre Mock-Einstellungen wie folgt ein:

ServiceLocator s = new ServiceLocator(); 
s->setGlobalSettings(new MockGlobalSettings()); 
ServiceLocator::load(s); 

Es ist ein Repository für Singletons, die zu Testzwecken ausgetauscht werden können.

0

Normalerweise wird dies durch eine Ini-Datei oder XML-Konfigurationsdatei behandelt. Dann haben Sie nur eine Klasse, die die Einstellung liest, wenn nötig.

.NET ist mit den ConfigurationManager-Klassen integriert, aber es ist ziemlich einfach zu implementieren, lesen Sie einfach Textdateien oder laden Sie XML in DOM oder parsen Sie sie manuell in Code.

Die Konfiguration der Dateien in der Datenbank ist in Ordnung, aber es verbindet Sie mit der Datenbank und erstellt eine zusätzliche Abhängigkeit für Ihre App, die ini/xml-Dateien lösen.

0

Ich tat dies:

public class MySettings 
{ 
    public static double Setting1 
     { get { return SettingsCache.Instance.GetDouble("Setting1"); } } 

    public static string Setting2 
     { get { return SettingsCache.Instance.GetString("Setting2"); } } 
} 

ich dieses Modul in einem separaten Infrastruktur stelle Probleme mit zirkulären Abhängigkeiten zu entfernen.
Dabei bin ich nicht an eine bestimmte Konfigurationsmethode gebunden, und keine Strings laufen in meinem Anwendungscode Chaos.

1

Ich möchte meinen Konfigurationszugriff aus dem Service Locator-Muster modellieren.Dies gibt mir einen einzigen Punkt, um irgendeinen Konfigurationswert zu erhalten, den ich benötige, und indem ich ihn außerhalb der Anwendung in eine separate Bibliothek lege, erlaubt er die Wiederverwendung und Testbarkeit. Hier ist ein Beispielcode, ich bin mir nicht sicher, welche Sprache Sie verwenden, aber ich habe sie in C# geschrieben.

Zuerst erstelle ich eine generische Klasse, die mein ConfigurationItem modelliert.

public class ConfigurationItem<T> 
{ 
    private T item; 

    public ConfigurationItem(T item) 
    { 
     this.item = item; 
    } 

    public T GetValue() 
    { 
     return item; 
    } 
} 

Dann erstelle ich eine Klasse, die öffentliche statische Readonly-Variablen für das Konfigurationselement verfügbar macht. Hier lese ich nur die ConnectionStringSettings aus einer Konfigurationsdatei, die nur XML ist. Natürlich können Sie für mehr Gegenstände die Werte von jeder Quelle lesen.

public class ConfigurationItems 
{ 
    public static ConfigurationItem<ConnectionStringSettings> ConnectionSettings = new ConfigurationItem<ConnectionStringSettings>(RetrieveConnectionString()); 

    private static ConnectionStringSettings RetrieveConnectionString() 
    { 
     // In .Net, we store our connection string in the application/web config file. 
     // We can access those values through the ConfigurationManager class. 
     return ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionKey"]]; 
    } 
} 

Dann, wenn ich ein Configuration Item für den Einsatz benötigen, nenne ich es wie folgt aus:

ConfigurationItems.ConnectionSettings.GetValue(); 

Und es wird mir eine Art sicheren Wert zurückgeben, die ich dann zwischengespeichert werden kann oder tun, was ich will mit .

Hier ist ein Beispieltest:

[TestFixture] 
public class ConfigurationItemsTest 
{ 
    [Test] 
    public void ShouldBeAbleToAccessConnectionStringSettings() 
    { 
     ConnectionStringSettings item = ConfigurationItems.ConnectionSettings.GetValue(); 
     Assert.IsNotNull(item); 
    } 
} 

Hoffnung, das hilft.