Можете ли вы ссылаться на другие агрегаты на фабрике при реализации доменного дизайна?
У меня есть два агрегата, Employee
а также Company
, Employee
хранит ссылку на Company
через это UUID
,
Если я хочу создать сотрудника, мне нужно предоставить его с идентификатором компании:
new Employee(name, companyId)
Что я не могу понять, так это как получить id
из Company
если клиент предоставляет только название компании. Другими словами, я вижу, что это происходит:
Employee buildEmployee(String name, String companyName) {
Company company = companyRepository.findByName()
return new Employeee(name, company.getGUID())
}
Что-то не так со мной, так как теперь я ввел зависимость от Company
агрегировать для того, чтобы создать Employee
, Еще хуже было бы то, что если бы это были две отдельные микросервисы, то мне пришлось бы сделать перезвон, чтобы узнать название компании.
Есть ли способ избежать этой связи, или мои объекты смоделированы неправильно?
3 ответа
То, что ваша модель в настоящее время выражает
Каждый сотрудник работает только в одной компании.
При этом совершенно ясно, что должна существовать Компания, прежде чем вы сможете создать Сотрудника.
Я вижу два разных решения, которые могут здесь соответствовать:
Передать компанию в
buildEmployee
, Это говорит о том, что для создания Сотрудника лучше всего нужна Компания.Пройдите в GUID компании. Это может подойти для случаев, когда у вас уже есть эта информация, но у вас нет всего объекта Company (например, создание сотрудника для существующего сотрудника).
Независимо от того, какой подход вы выберете, вы должны избегать загрузки данных через хранилище на заводе. Лучше оставить это для вызывающей службы приложения, потому что службе приложения в любом случае может потребоваться Компания (например, для некоторой проверки ввода).
Сохранение всего взаимодействия с репозиторием в службе приложений сделает ваше приложение более надежным и легким для рассуждения. В конце концов, доступ к хранилищу обычно включает в себя сетевое взаимодействие и задержку.
Подводя итог, нет ничего плохого в том, чтобы иметь зависимость от Компании отbuildEmployee
, но вы должны избегать вызова хранилища.
Если в зависимости от компании все еще чувствует себя не так, то вам следует пересмотреть свою модель.
Использование репозитория внутри фабрики, как правило, не очень хорошая идея, поскольку оно скрывает от потребления кода (т. Е. Службы приложений) тот факт, что другой агрегат заносится в таблицу и используется в текущей транзакции.
Но это не значит, что привлечение другого агрегата всегда плохо. Вы должны принять обоснованное решение:
Вы могли бы на самом деле нужно
Company
быть частью бизнес-транзакции, которая создает новыйEmployee
, Вы могли бы хотеть этого, потому чтоCompany
содержит доменные инварианты о сотрудниках (например, список уникальных электронных писем сотрудников) или потому, что созданиеEmployee
меняет вещи внутриCompany
само по себе, и вы хотите предотвратить одновременное создание работника, чтобы испортить ситуацию в компании.Есть несколько способов сделать это, но было бы неплохо иметь
createEmployee()
метод в самой компании, так как оба связаны.Или вы не заботитесь о
Company
(кроме его идентификатора) при созданииEmployee
, Вы можете подумать, что вам не нужна немедленная согласованность между существующей компанией и сотрудником. Или, если у вас есть внешние ключи в вашей базе данных, они уже обеспечивают достаточную защиту, чтобы предотвратить создание сиротских сотрудников.В этом случае просто сохраняйте companyID как единственный указатель на компанию от интерфейса пользователя до домена. Вам даже не нужно использовать
CompanyRepository
загрузить компанию, потому что она не участвует в процессе.
Сначала подумайте о вашей модели: вы уверены, что сотрудник работает только в одной компании? И что эта компания никогда не изменится?
На ваш реальный вопрос я не вижу реальной проблемы; Итак, позвольте мне процитировать из " DDD быстро ":
Есть моменты, когда строительство объекта является более сложным. ...
Представляется целесообразным использовать специальный класс Factory, который выполняет задачу создания всего Aggregate и который будет содержать правила, ограничения и инварианты, которые должны применяться для того, чтобы Aggregate был действительным. Объекты останутся простыми и будут выполнять свои конкретные задачи без беспорядка сложной строительной логики.
Одним из решений может быть добавление еще одного слоя - тот, который делает этот поиск для вас; и вызывает ваш метод buildEmployee() напрямую с UUID компании.