Acces la setările aplicațiilor globale

O aplicație de bază de date la care lucrez în prezent stochează tot felul de setări din baza de date. Cele mai multe dintre aceste setări sunt acolo pentru a personaliza anumite reguli de afaceri, dar există și alte lucruri acolo.

Aplicația conține obiecte care fac în mod specific o anumită sarcină, de exemplu, un anumit calcul complicat. Aceste obiecte non-UI sunt testate pe unitate, dar au și nevoie de acces la o mulțime de setări globale. Modul în care am implementat acest lucru chiar acum este prin oferirea proprietăților obiectelor care sunt umplute de controlerul de aplicații în timpul execuției. La testare, vom crea obiectele din test și vom completa valorile pentru testare (nu din baza de date).

Acest lucru funcționează mai bine, în orice caz mult mai bine decât dacă toate obiectele au nevoie de un obiect global Setări care, desigur, face ca testarea unității să fie imposibilă :) Dezavantajul poate fi că uneori trebuie să setați o duzină de proprietăți sau de care aveți nevoie pentru a permite aceste proprietăți să "percolate" în sub-obiecte.

So the general question is: how do you provide access to global application settings in your projects, without the need for global variables, while still being able to unit test your code? This must be a problem that's been solved 100's of times...

(Notă: Nu sunt prea mult de un programator experimentat, așa cum ați fi observat, dar îmi place să învăț și, bineînțeles, am făcut deja cercetări în acest subiect, dar eu chiar caut unii - experiente de mana)

0
fr hi bn

4 răspunsuri

De obicei, acest lucru este tratat de un fișier inițial sau de fișier de configurare XML. Apoi, aveți doar o clasă care citește setarea atunci când este neeed.

.NET are această construcție cu clasele ConfigurationManager, dar este destul de ușor de implementat, citiți doar fișiere text sau încărcați xml în DOM sau parsezi-le manual.

Având fișiere de configurare în baza de date este în regulă, dar vă va lega la baza de date și creează o dependență suplimentară pentru aplicația dvs. care rezolvă fișierele ini/xml.

0
adăugat

Am facut asta:

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

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

Am pus acest lucru într-un modul de infrastructură separat pentru a elimina orice probleme cu dependențe circulare Făcând acest lucru, nu sunt legată de nicio metodă specifică de configurare și nu am niciun șir de caractere care să se poată deranja în codul aplicațiilor mele.

0
adăugat

Îmi place să modelez accesul la configurația mea din modelul Locator de servicii. Acest lucru îmi dă un singur punct pentru a obține orice valoare de configurare de care am nevoie și prin plasarea acesteia în afara aplicației într-o bibliotecă separată, permite reutilizarea și testabilitatea. Iată câteva exemple de cod, nu sunt sigur ce limbă folosiți, dar l-am scris în C #.

Mai întâi creez o clasă generică care îmi va modela ConfigurationItem.

public class ConfigurationItem
{
    private T item;

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

    public T GetValue()
    {
        return item;
    }
}

Apoi, creez o clasă care expune variabilele cititoare statice publice pentru elementul de configurare. Aici citesc doar ConnectionStringSettings dintr-un fișier config, care este doar xml. Desigur, pentru mai multe articole, puteți citi valorile din orice sursă.

public class ConfigurationItems
{
    public static ConfigurationItem ConnectionSettings = new ConfigurationItem(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"]];
    }
}

Atunci când am nevoie de un ConfigurationItem pentru utilizare, o spun așa:

ConfigurationItems.ConnectionSettings.GetValue();

Și mi se va întoarce o valoare sigură de tip, pe care o pot apoi să cache sau să fac tot ce vreau.

Iată un test de probă:

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

Sper că acest lucru vă ajută.

0
adăugat

Ai putea folosi modelul Martin Fowlers ServiceLocator. În PHP ar putea arăta astfel:

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;
  }
}

Codul dvs. de producție inițializează locatorul de servicii astfel:

ServiceLocator::load(new ServiceLocator());

În codul dvs. de test, introduceți setările de mock-uri astfel:

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

Este un depozit pentru single-uri care pot fi schimbate în scopuri de testare.

0
adăugat