Почему бы не использовать контейнер IoC для разрешения зависимостей для сущностей / бизнес-объектов?

Я понимаю концепцию, лежащую в основе 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);
    }
}

Как вы можете видеть, зависимости являются Constructor Injected. Теперь пара вопросов.

  1. Считается ли плохой практикой, что ваши сущности зависят от внешних классов, таких как ShipQuoter? Устранение этих зависимостей, кажется, ведет меня к анемичной области, если я правильно понимаю определение.

  2. Является ли плохой практикой использование контейнера IoC для разрешения этих зависимостей и создания сущности при необходимости? Можно ли сделать это?

Спасибо за понимание.

2 ответа

Решение

На первый вопрос ответить сложнее всего. Это плохая практика, когда сущности зависят от внешних классов? Это, конечно, не самая распространенная вещь.

Например, если вы внедряете репозиторий в свои сущности, у вас фактически есть реализация шаблона Active Record. Некоторым людям нравится этот шаблон за удобство, которое он предоставляет, в то время как другие (как я) считают это запахом кода или анти-шаблоном, потому что он нарушает принцип единой ответственности (SRP).

Вы можете утверждать, что введение других зависимостей в сущности приведет вас в том же направлении (от SRP). С другой стороны, вы, безусловно, правы, что если вы этого не сделаете, то стремление к анемичной доменной модели.

Я долго боролся со всем этим, пока не наткнулся на (заброшенную) статью Грега Янга о DDDD, где он объясняет, почему стереотипная архитектура n-уровня /n-слоя всегда будет CRUDy (и, следовательно, довольно анемичной).

Сосредоточение нашего внимания на моделировании объектов Домена как Команд и Событий вместо Существительных, кажется, позволяет нам построить правильную объектно-ориентированную модель предметной области.

На второй вопрос легче ответить. Вы всегда можете использовать Abstract Factory для создания экземпляров во время выполнения. С Castle Windsor вы даже можете использовать Typed Factory Facility, освобождая вас от бремени внедрения фабрик вручную.

Я знаю, что это старый пост, но хотел добавить. Сущность домена не должна сохраняться сама по себе, даже если вы передаете абстрагированный репозиторий в ctor. Причина, по которой я высказываю предположение, заключается не только в том, что это нарушает SRP, но и противоречит агрегации DDD. Позвольте мне объяснить, DDD подходит для сложных приложений с глубокими графами, поэтому мы используем агрегированные или составные корни для сохранения изменений в базовых "потомках", поэтому, когда мы внедряем постоянство в отдельных детей, мы нарушаем отношения, которые дети имеют к составной или совокупный корень, который должен "отвечать" за жизненный цикл или агрегацию. Конечно, составной корень или агрегат также не сохраняют свой собственный граф. Еще одна проблема с внедрением зависимостей объектов DDD заключается в том, что внедренный объект домена фактически не имеет состояния, пока не произойдет какое-либо другое событие для увлажнения его состояния. Любой потребитель кода будет вынужден сначала инициировать или настроить объект домена, прежде чем он сможет вызвать деловое поведение, которое нарушает инкапсуляцию.

Другие вопросы по тегам