Настраиваемые свойства отображения для моделей домена
Использование DDD и следование шаблону чистой архитектуры, и я немного запутался в том, где идеальное место для настройки свойств отображения для конкретных идентификаторов модели домена. Это звучит странно, я думаю, что лучше всего объяснить это на примере:
Здесь бизнес-логика модели предметной области проста: вычисляется "масштабированное" значение на основе входных данных, коэффициента усиления и смещения.
//Domain Model
public class Transducer
{
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
У нас есть сценарий использования, который координирует действия пользователя с моделями доменов и управляет постоянством. Детали здесь не важны, поэтому я включил только пример интерфейса:
//implementation of execution of business logic and persistance would go in the implentation, details left out for this example
public interface ITransducerUseCase
{
IEnumerable<string> GetAllTransducerNames();
void AddNewTransducer(string Name, double Gain, double Offset);
void SetGain(string Name, double Gain);
void SetOffset(string Name, double Offset);
void SetRawValue(string Name, double Raw);
double GetScaledValue(string Name);
}
Вариант использования используется контроллером для координации вариантов использования с представлением или другим контроллером. Этот конкретный контроллер позволяет просматривать все имена преобразователей и может изменять их свойство Gain.
public class Controller
{
ITransducerUseCase _TransducerUseCase;
//these are sent to the view to be displayed
public Dictionary<string, double> _transducerScaledValues = new Dictionary<string, double>();
public Controller(ITransducerUseCase TransducerUseCase)
{
_TransducerUseCase = TransducerUseCase;
//Get all the names and populate the dictionary to display.
foreach (var transducerName in _TransducerUseCase.GetAllTransducerNames())
_transducerScaledValues.Add(transducerName, _TransducerUseCase.GetScaledValue(transducerName));
}
//bound to the view
public string SelectedName { get; set; }
//bound to the view, a property for setting a new gain value
public double Gain { get; set; }
public void OnButtonClick()
{
//update the gain
_TransducerUseCase.ChangeGain(SelectedName, Gain);
//get the new scaled value
_transducerScaledValues[SelectedName] = _TransducerUseCase.GetScaledValue("PumpPressure");
}
}
Это строительные леса для этого вопроса. Вот новое требование:
Мы хотим иметь параметр конфигурации уровня приложения для "количества десятичных разрядов", которое отображается для
ScaledValue
изTransducer
на основе идентичности. Таким образом, преобразователь с идентификатором "PumpPressure" может иметь другое значениеDisplayRounding
чем преобразователь с названием "PumpTemperamer".Этот параметр должен быть общедоступным (каждый раз, когда отображается значение, используйте этот параметр). Эту настройку также можно использовать, если
ScaledValue
был когда-либо зарегистрирован в файл, так что это сквозная потребность бизнеса.
Решения, о которых я подумал: размещение свойства в доменной модели и возвращение его через слои в представление. Это не похоже на логичное место, потому что DisplayRounding
свойство не имеет никакого отношения к бизнес-логике.
public class Transducer
{
//This seems like an SRP violation
public int DisplayRounding { get; set; }
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
Если не там, то где?
Можем ли мы поместить ее в отдельную модель предметной области без какой-либо бизнес-логики? Постоянство может управляться тем же классом сценариев использования или отдельным классом.
public class TransducerDisplaySettings
{
public int Rounding { get; set; }
//plus other related properties
}
Плюсы: он лучше разделяет проблемы, чем одна объединенная модель.
Минусы: модель не имеет бизнес-логики, это нормально?
Мы также рассмотрели возможность полного управления этими настройками на внешних уровнях с помощью какого-либо сервиса.
Плюсы: нет доменных моделей без бизнес-логики
Минусы: Возможно, будет привязан к конкретной структуре?
Есть ли еще плюсы / минусы, по которым я скучаю? Один подход явно лучше другого? Есть ли подход, который я полностью пропустил? Спасибо!
1 ответ
Главное решение, которое вам нужно будет принять, заключается в том, является ли округление отображения аспектом бизнес-логики ваших приложений или "просто аспектом отображения".
В случае, если вы считаете это важным для вашей бизнес-логики, его следует смоделировать с вашими сущностями.
В случае, если вы рассматриваете это просто как аспект "представления значений пользователю" (что не относится к бизнес-правилам), его следует сохранить в отдельном репозитории или службе, а затем применить "докладчик".
[table("NameTable")]
public class Transducer
{
//Name is the ID
[Key] //is Key from table
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}