Корень агрегата DDD - это правильно иметь статический метод, который создает объект
Правильно ли иметь такой метод Create? Или я должен создать пользователя внутри службы вместо. Это разрушает концепцию DDD?
Каковы лучшие практики для подобных ситуаций?
Примечание: я тоже использую DI.
public class User : HistoryBase, IAggregateRoot
{
private IEnumerable<Role> _roles = new List<Role>();
public string Name { get; protected set; }
public string Lastname { get; protected set; }
public string Email { get; protected set; }
public string Password { get; protected set; }
public string EmployeeNumber { get; protected set; }
public bool Active { get; protected set; }
public int SiteID { get; protected set; }
public IEnumerable<Role> Roles { get { return _roles; } }
public static User Create(string name, string lastname, string email, string password, string employeeNumber, Site site)
{
var user = new User()
{
Name = name,
Lastname = lastname,
Email = email,
Password = password,
EmployeeNumber = employeeNumber,
SiteID = site.ID
};
return user;
}
}
2 ответа
DDD в основном касается именования ваших классов и их свойств, чтобы они точно отражали ту часть бизнес-сферы, которую должно представлять ваше программное обеспечение.
Это действительно не диктует какие-либо технические детали реализации, такие как, например, создание объектов. Дело в том, что свойства и методы класса имеют значение в домене.
Статический .Create()
Метод не имеет смысла с точки зрения области, но и не имеет new ..()
вызов к конструктору.
Вы можете принять решение, что метод построения для ваших доменных сущностей / агрегатов должен быть Class.Create()
вместо new Class()
,
Это не "неправильно"
Если, например, используемые вами фреймворки / библиотеки требуют общедоступного конструктора по умолчанию без параметров (общего с такими вещами, как EntityFramework и некоторые библиотеки сериализации), и вы хотите, чтобы ваш "стандартный" метод создания экземпляров был однозначным (может вызываться только со всеми необходимыми параметрами)), это совершенно верный способ сделать это.
Просто будьте последовательны
Если вы делаете это, вы должны делать это для всех ваших сущностей / агрегатов. Это становится соглашением, и оно будет задокументировано как техническая деталь реализации (как конструктор по умолчанию).
Используйте CommandHandlers, а не сервисы (или фабрики)
Сервисы не предназначены для создания экземпляров классов (для этого нужны фабрики).
Тем не менее, ваш код, похоже, намекает на то, что вы также применяете EventSourcing или некоторые его варианты. Предполагая, что вы также делаете CQRS, у вас есть Create
Команды, заканчивающиеся в ваших CommandHandlers Create
методы. Вот где вы могли бы разместить такие вещи, как логика проверки, если вам это нужно.
Таким образом, эти CommandHandlers уже являются вашими фабриками, для этого вам не нужен дополнительный слой.
И, наконец:
Подобные статические методы создания экземпляров обычно используются для реализации некоторого Fluent API, например, с шаблоном Builder. Он предлагает синтаксический сахар для цепочки вызовов.
Таким образом, это может создать у других разработчиков / потребителей ложное впечатление, что вызов может быть прикован цепью (что в вашем примере не может).
Вы, вероятно, по-прежнему захотите определить открытый конструктор по умолчанию, так что вы можете иметь комментарий к документации, чтобы НЕ использовать его, и иметь один на .Create()
что это должно быть использовано в качестве конструктора.
Учитывая все вышесказанное, все же лучше, чем просто использовать конструктор? Тогда непременно сделайте это. Насколько я знаю, это не влияет на "DDD-ность".
Правильно ли иметь такой метод Create?
В целом это нормально.
Уди Даан отметил, что "создать" и "новый" обычно не являются частью языка предметной области, поэтому он предложил совет " Не создавать совокупные корни"
Клиенты не просто появляются из воздуха.
То есть поведение вашего домена должно точно описывать, как новая информация вводится в систему.
Дополнительный уровень косвенности между конструктором и потребляющим кодом может уменьшить ненужную связь - именованные конструкторы, фабричные методы и компоновщики, которые возвращают интерфейсы, дают вам гибкость для изменения или декорирования возвращаемого объекта. Но это общий принцип модульности / разделения интересов, а вовсе не специфический для доменного дизайна.
Я хотел бы пойти с чем-то, что более четко заявляет, что вы делаете, а не Create
, Похоже, вы регистрируете сотрудника на веб-сайте. Попробуйте сказать это так, как если бы кто-то, кто будет использовать систему, сказал бы.
Если они скажут: "Эй, ты создашь этого пользователя". Тогда ваш метод в порядке.
Если они скажут: "Эй, вы зарегистрируете этого сотрудника на нашем сайте?" Затем вы должны использовать:
public static Employee RegisterOnWebsite(string name, string lastname, string email, string password, string employeeNumber, Site site)
{
// Creation Code
}
Так как у вас есть номер сотрудника в собственность. Кажется, этот пользователь всегда будет сотрудником. Вы должны прояснить это и назвать это так. Теперь ваш метод будет читать как, Employee.RegisterOnWebsite(...)
,