Использование настроек уровня приложения в моделях с расширенным набором доменов
Я хочу иметь глобальную настройку / настройку уровня приложения, которую я хочу использовать в своих моделях доменного имени.
У меня есть метод, который делает некоторые вычисления на основе переданного аргумента.
Это может быть не лучшим примером и может не выглядеть как метод, принадлежащий модели предметной области, но я стараюсь сделать его простым, чтобы вы могли понять проблему.
public decimal Calculate(CalculationMethod calculationMethod)
{
switch (calculationMethod)
{
case CalculationMethod.Multiply:
return _x * _y; // _x and _y are fields
case CalculationMethod.Divide:
return _x / _y;
}
}
Теперь допустим, что у меня есть много методов, подобных этому, в других моих моделях доменов, которые также принимают CalculationMethod
в своих методах. Я хотел бы иметь глобальную настройку, чтобы я мог установить метод вычисления глобально, чтобы он мог использоваться всеми методами, которые принимают его в качестве параметра.
Одним из решений будет чтение конфигурации каждый раз, когда я вызываю этот метод.
Интересно, есть ли лучший способ, чтобы я мог установить CalculationMethod
глобально и никогда не передавайте его, и вместо этого, имея какую-то статическую переменную (синглтон), которая содержит метод вычисления и читает его непосредственно в моих методах, не передавая его. Но я думаю, что тогда возникнет проблема безопасности потоков.
public decimal Calculate()
{
// or read it from file here?
switch (GlobalSettings.CalculationMethod)
{
case CalculationMethod.Multiply:
return _x * _y; // _x and _y are fields
case CalculationMethod.Divide:
return _x / _y;
}
}
Я не могу передать это в конструкторе, потому что это не то, что принадлежит моей модели предметной области.
Как подойти к такой проблеме? Есть ли способ лучше, чем два, которые я упомянул?
Я задал этот вопрос в комментарии под ответом Марка Симанна: Настройки уровня приложения в DDD?
1 ответ
Как объясняет Чистый код, передача флагов методам обычно считается неоптимальным дизайном. Я понимаю, что OP является заменой для другой, более сложной проблемы, но я был бы склонен рекомендовать рефакторинг к полиморфной объектной модели:
public interface ICalculator
{
decimal Calculate();
}
Теперь вы можете определить реализации как требуется:
public class Multiplier : ICalculator
{
public decimal Calculate()
{
return _x * _y; // _x and _y are fields
}
}
public class Divider : ICalculator
{
public decimal Calculate()
{
return _x / _y;
}
}
Вы можете ввести ICalculator
Объект в любой класс, который нуждается в этом, используя Constructor Injection. В корне композиции вы можете прочитать файл конфигурации или каким-либо другим способом решить, какую реализацию использовать, а затем создать только один экземпляр этого класса. Это дает объекту единичное время жизни, так что метод расчета полностью выбирается во время запуска и распределяется между всеми объектами в приложении.