Сведения о вопросе

DUNKER

00:30, 27th August, 2020

Теги

Доступ к глобальным настройкам приложения

Просмотров: 418   Ответов: 4

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

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

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

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

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



  Сведения об ответе

P_S_S

23:39, 29th August, 2020

Вы можете использовать шаблон Martin Fowlers 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);

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


  Сведения об ответе

LIZA

13:43, 24th August, 2020

Мне нравится моделировать свой доступ к конфигурации на основе шаблона локатора служб. Это дает мне одну точку для получения любого значения конфигурации, которое мне нужно, и, поместив его вне приложения в отдельную библиотеку, он позволяет повторно использовать и тестировать. Вот некоторые примеры кода, я не уверен, на каком языке вы используете, но я написал его в 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);
    }
}

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


  Сведения об ответе

prince

19:35, 18th August, 2020

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

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

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


  Сведения об ответе

nYU

08:33, 10th August, 2020

Я сделал это сам:

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

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться