Доступ к глобальным настройкам приложения - PullRequest
2 голосов
/ 15 августа 2008

Приложение базы данных, над которым я сейчас работаю, хранит все виды настроек в базе данных. Большинство из этих настроек предназначены для настройки определенных бизнес-правил, но есть и другие вещи.

Приложение содержит объекты, которые конкретно выполняют определенную задачу, например, определенный сложный расчет. Эти объекты не-пользовательского интерфейса проходят модульное тестирование, но им также необходим доступ ко многим из этих глобальных настроек. Мы реализовали это прямо сейчас, предоставив свойства объектов, которые заполнены Application Controller во время выполнения. При тестировании мы создаем объекты в тесте и вводим значения для тестирования (не из базы данных).

Это работает лучше, в любом случае гораздо лучше, чем для всех этих объектов требуется какой-то глобальный Настройки объект --- что, конечно, эффективно делает невозможным юнит-тестирование :) Недостатком может быть то, что вам иногда нужно установить дюжина свойств или то, что вам нужно, чтобы эти свойства «просачивались» в подобъекты.

Таким образом, общий вопрос : как вы предоставляете доступ к глобальным настройкам приложения в своих проектах, не нуждаясь в глобальных переменных, и в то же время сохраняя возможность модульного тестирования своего кода? Это должно быть проблема, которая была решена 100 раз ...

(Примечание: я не слишком опытный программист, как вы заметили; но я люблю учиться! И, конечно, я уже провел исследование этой темы, но я действительно ищу для личного опыта)

Ответы [ 4 ]

1 голос
/ 15 августа 2008

Мне нравится моделировать мой доступ к конфигурации из шаблона Service Locator. Это дает мне возможность получить любое значение конфигурации, которое мне нужно, и, поместив его вне приложения в отдельную библиотеку, позволяет повторно использовать и тестировать. Вот пример кода, я не уверен, какой язык вы используете, но я написал его на C #.

Сначала я создаю универсальный класс, который будет моделировать мой ConfigurationItem.

public class ConfigurationItem<T>
{
    private T item;

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

    public T GetValue()
    {
        return item;
    }
}

Затем я создаю класс, который предоставляет общедоступные статические переменные только для чтения для элемента конфигурации. Здесь я просто читаю ConnectionStringSettings из файла конфигурации, который является просто XML. Конечно, для большего количества элементов вы можете прочитать значения из любого источника.

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

Затем, когда мне нужен ConfigurationItem для использования, я называю его так:

ConfigurationItems.ConnectionSettings.GetValue();

И он вернет мне безопасное значение типа, которое я могу затем кэшировать или делать с чем захочу.

Вот пример теста:

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

Надеюсь, это поможет.

1 голос
/ 15 августа 2008

Вы можете использовать шаблон ServiceLocator Мартина Фаулера. В php это может выглядеть так:

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

Затем ваш производственный код инициализирует указатель службы следующим образом:

ServiceLocator::load(new ServiceLocator());

В своем тестовом коде вы вставляете свои макеты-настройки следующим образом:

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

Это хранилище для синглетонов, которое можно обменять для тестирования.

0 голосов
/ 15 августа 2008

Я сделал это:

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

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

Я поместил это в отдельный модуль инфраструктуры, чтобы устранить любые проблемы с циклическими зависимостями.
При этом я не привязан к какому-либо конкретному методу конфигурации, и у меня нет кодов, запускающих хаос в коде моих приложений.

0 голосов
/ 15 августа 2008

Обычно это обрабатывается INI-файлом или XML-файлом конфигурации. Тогда у вас просто есть класс, который читает параметр при необходимости.

.NET имеет это встроенное в классы ConfigurationManager, но его довольно легко реализовать, просто читая текстовые файлы или загружая XML в DOM или анализируя их вручную в коде.

Наличие файлов конфигурации в базе данных - это нормально, но оно связывает вас с базой данных и создает дополнительную зависимость для вашего приложения, которую решают файлы ini / xml.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...