Почему бы не использовать контейнер 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. Теперь на пару вопросов.

  • Является ли плохая практика, чтобы ваши объекты зависели от внешних классов, таких как ShipQuoter? Устранение этих зависимостей, по-видимому, приводит меня к анемическому домену, если я правильно понимаю определение.

  • Неправильно ли использовать контейнер IoC для разрешения этих зависимостей и при необходимости создавать объект? Возможно ли это сделать?

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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