#domain-driven-design
Вопрос:
У меня есть вопрос об обратной зависимости между совокупным корнем (AR). Когда связь между двумя совокупными корнями была определена, т. Е. После некоторой операции было установлено или изменено отношение 1-1 или 1-N. Откуда обратное отношение знает о своем существовании, когда вам разрешено изменять только один совокупный корень.
Моя проблема в том, что другой совокупный корень использует бизнес-логику, которая зависит от обратной зависимости между совокупными корнями.
Приведенный ниже код является примером, поэтому, возможно, используемые имена могут быть немного странными, но важной частью является взаимосвязь между AR. Для примера я использую два агрегированных корня: Человек и Организация и занятость как бизнес-процесс. Проблема в том, что поведение задает только одну сторону отношения. Таким образом, пример:
class Organization
{
// parameter is a value object representing the Person AR.
public function startEmployment(Person $person)
{
if (in_array($person, $this->employees)) {
throw new Exception("Person is already an employee");
}
$this->employees[] = $person;
}
}
В приведенном выше примере я могу изменить один AR, и бизнес-логика находится в нужном месте. Но когда я смотрю на другого AR, таким образом, Человека, я обнаруживаю некоторые проблемные области. Например, когда бизнес-требование таково: Человек не может менять место жительства при приеме на работу (мог бы придумать лучший пример).
class Person
{
public function changeLivingLocation(Location $location)
{
// what information and where do i get it from?
if (...) {
throw new Exception("May not change living location");
}
$this->livingLocation = $location;
}
}
В комментарии уже описана проблема. Откуда я могу получить информацию? Организация AR содержит всю информацию о трудоустройстве. Самое простое решение-запросить организационную таблицу, но затем я представляю уровень инфраструктуры на уровне домена. Это противоречит принципам чистой архитектуры (или другим примерам DDD, которые я видел). Я мог бы ввести доменную службу, которая выполняет бизнес-логику, но затем в рамках доменной службы я мог бы запросить репозиторий/службу Организации. Хотя, все еще есть что-то из уровня инфраструктуры, упомянутого в доменном слое.
Вопрос(ы):
- Как я могу получить информацию из обратной зависимости, когда связь определяется в другом совокупном корне? Или когда агрегатному корню требуется агрегированный результат (например, количество какой-либо сущности).
- Как я могу получить эту информацию из-за пределов домена, когда я нахожусь на уровне домена?
// Обновление после прочтения первого ответа После прочтения ответа и оценки идеи о том, что интерфейс репозитория существует на уровне домена, я переместил его в доменную службу. По крайней мере, для того, как я сейчас вижу доменную службу. Я могу выполнить следующую реализацию: политика оценивает бизнес-логику, которая основана на количестве репозиториев .
class Person
{
public function changeLivingLocation(MayChangeLocation $policy, Location $location)
{
if ($policy->evaluate ($this)) {
throw new Exception("May not change living location");
}
$this->livingLocation = $location;
}
}
class MayChangeLocation // effective the domain service
{
public function __construct(RepositoryInterface $repository) {
$this->repository = $repository;
}
public function evaluate (Person $person)
{
$organizations = $this->repository->getOrganzationsEmployesPerson($person->getId());
// here real business logic is applied
if (count($organizations) > 0) {
return false;
}
return true;
}
}
Просто любопытно узнать о комментариях к отзывам 🙂
Ответ №1:
Самое простое решение-запросить организационную таблицу, но затем я представляю уровень инфраструктуры на уровне домена.
Это то, что вы должны делать, не через уровень инфраструктуры, а через запрос на уровне домена.
Вы можете передать репозиторий для загрузки Organization
AR в Person
один, или использовать сервис, или Query
в терминах CQRS.
Комментарии:
1. Прочитав ваш комментарий, я позволил ему утонуть и предложил возможное решение. Мне любопытно, как вы об этом думаете.
2. да, это хороший подход. Только одно, в случае, если вы создаете метод
getOrganzationsEmployesPerson
только для этого случая использования или хотите получить более высокую производительность,countOrganzationsEmployesPerson
вместо этого будет лучше использовать метод, так как вы избегаете загружать весь список из бд.3. Сбился с курса! Спасибо!