Я понимаю концепцию DI, но я только изучаю, что могут делать разные контейнеры IoC. Кажется, что большинство людей выступает за использование контейнеров IoC для подключения сервисов без сохранения состояния, но как насчет их использования для объектов с сохранением состояния, таких как сущности?
Правильно это или нет, я обычно наполняю свои сущности поведением, даже если для этого поведения требуется внешний класс. Пример:
public class Order : IOrder
{
private string _ShipAddress;
private IShipQuoter _ShipQuoter;
public Order(IOrderData OrderData, IShipQuoter ShipQuoter)
{
// OrderData comes from a repository and has the data needed
// to construct order
_ShipAddress = OrderData.ShipAddress; // etc.
_ShipQuoter = ShipQuoter;
}
private decimal GetShippingRate()
{
return _ShipQuoter.GetRate(this);
}
}
Как видите, зависимости введены конструктором. Теперь пара вопросов.
Считается ли плохой практикой, чтобы ваши объекты зависели от внешних классов, таких как ShipQuoter? Если я правильно понимаю определение, устранение этих зависимостей ведет меня к анемичной области.
Является ли плохой практикой использование контейнера IoC для разрешения этих зависимостей и создания объекта при необходимости? Можно ли это сделать?
Спасибо за понимание.
Ответы:
На первый вопрос ответить труднее всего. Это плохая практика, когда сущности зависят от внешних классов? Конечно, это не самое обычное дело.
Если, например, вы внедряете репозиторий в свои сущности, у вас фактически есть реализация шаблона Active Record . Некоторым людям нравится этот шаблон за удобство, которое он обеспечивает, в то время как другие (например, я) считают его запахом кода или анти-шаблоном, поскольку он нарушает принцип единой ответственности (SRP).
Вы могли бы возразить, что внедрение других зависимостей в Entities потянет вас в том же направлении (от SRP). С другой стороны, вы определенно правы в том, что, если вы этого не сделаете, тяга будет направлена на модель анемической области .
Я долго боролся со всем этим, пока не наткнулся на (заброшенную) статью Грега Янга о DDDD, где он объясняет, почему стереотипная n-уровневая / n-слойная архитектура всегда будет CRUDy (и, следовательно, довольно анемичной).
Смещение нашего фокуса на моделирование объектов домена в виде команд и событий вместо существительных, кажется, позволяет нам построить правильную объектно-ориентированную модель домена.
На второй вопрос ответить легче. Вы всегда можете использовать абстрактную фабрику для создания экземпляров во время выполнения . С Castle Windsor вы даже можете использовать типизированную фабрику, избавляя вас от бремени создания фабрик вручную.
источник
Я знаю, что это старый пост, но хотел добавить. Сущность домена не должна сохраняться, даже если вы передаете абстрактный репозиторий в ctor. Причина, по которой я предлагаю это, заключается не только в том, что это нарушает SRP, это также противоречит агрегированию DDD. Позвольте мне пояснить, что DDD подходит для сложных приложений с глубокими графами, поэтому мы используем агрегированные или составные корни для сохранения изменений в базовых «дочерних элементах», поэтому, когда мы вводим настойчивость в отдельные дочерние элементы, мы нарушаем отношения, которые дети имеют с составной или совокупный корень, который должен «отвечать» за жизненный цикл или агрегацию. Конечно, составной корень или агрегат также не сохраняет свой собственный граф. Другой - с внедрением зависимостей объектов DDD, заключается в том, что внедренный объект домена фактически не имеет состояния, пока не произойдет какое-либо другое событие для гидратации его состояния. Любой потребитель кода будет вынужден сначала инициализировать или настроить объект домена, прежде чем он сможет вызвать бизнес-поведение, которое нарушает инкапсуляцию.
источник