Ассоциация Доменных Моделей Ленивая Загрузка
В настоящее время я сталкиваюсь с проблемой обработки ассоциаций между сущностями в совокупности.
Рассмотрим следующий пример:
Прямо сейчас у нас есть объект "Пользователь", который также является моим совокупным корнем. У него может быть ровно один "Продукт", связанный с ним, и много "Псевдонимов". В настоящее время мне нужна возможность поиска связанных "Продукт" и "Псевдонимы" по запросу в доменной модели. Пользователь создается UserFactory, которую можно использовать отдельно или также в UserRepository при создании сущностей из данных в постоянном режиме.
<?php
class User {
private $id;
private $aliases;
private $product;
public function isEligibleForCompanyPromotion() {
//I need a good way to populate this without a performance bottleneck.
$product = $this->product;
[.. code comparing things between User and Product begins ..]
}
}
Причина этого заключается в том, что наша бизнес-логика (как вы можете видеть в примере) во многом зависит от ассоциаций между объектами, и я полагаю, что эта логика, связанная с ассоциациями между объектами, должна выполняться в рамках модели предметной области (или, возможно, ее следует исключить?)
Я рассмотрел следующие решения:
1) Просто загрузите все (связанный продукт и псевдонимы), когда создается пользователь.
Плюсы:
- Работает?
Минусы:
- БОЛЬШАЯ проблема производительности (и, к сожалению, я работаю над живой системой с высокой нагрузкой, так что от этого нельзя отказаться)
2) Внедрить хранилище отношений в модель предметной области
private $productRepository;
private $aliasesRepository;
[...]
}
Плюсы:
- Работает..
Минусы:
- Поражает ( imo) цель DDD, при этом от пользователя требуется наличие репозиториев внутри (поэтому модель домена связана с постоянством..)
3) Делегировать связанную с ассоциацией логику из доменной модели (может быть, в доменные службы и политики?)
Плюсы:
- Также работает
Минусы:
- На самом деле я чувствую, что это приводит к анемичным моделям доменов, потому что большая часть нашей бизнес-логики основана на отношениях объектов, поэтому большая часть кода будет перемещена из доменных объектов, что не имеет смысла.
4) Создайте специальный объект Relationship для обработки отношения:
<?php
class UserFactory {
private $relationshipFactory;
public function createUser($persistenceData) {
$user = new User();
[.. creating of User, populating data etc .. ]
$user->product = $this->relationshipFactory->createUserProductRelationship($user);
}
}
class UserProductRelationship {
private $user;
private $product;
private $productRepository;
[.. productRepository is being injected within relationshipFactory, and user is provided ..]
public function loadProduct() {
[.. load the product based on the relationship criterias ..]
}
[.. calls to this object are proxied to lazy-loaded product via __call, __get etc. )
}
Плюсы:
- Также работает
Минусы:
- Круговая зависимость (пользователь должен иметь внутри UserProductRelationship и полагаться на него. UserProductRelationship должен быть предоставлен с сущностью User. Объединение этих двух классов приведет к сценарию № 2).
Может быть, я что-то не поняла правильно... если у кого-нибудь есть предложение, я буду рада услышать об этом.
Спасибо!
1 ответ
Ввести объект спецификации, если некоторая ответственность не принадлежит какому-либо объекту или объекту домена требуется слишком много несвязанных данных для решения проблемы.
То, что вам нужно, - это ElptableForCompanyPromotionSpecification, например:
class EligibleForCompanyPromotion {
private $productRepository;
private $aliasesRepository;
public function isSatisfiedBy(User user) {
//I need a good way to populate this without a performance bottleneck.
$product = $productRepository.find(user.productId);
[.. code comparing things between User and Product begins ..]
}
class User {
private $id;
private $aliasesId;//only identifiers needed
private $productId;//only identifiers needed
В этом случае логика домена не просачивается на прикладной уровень, и нам не нужно внедрять репозитории в пользователя.