Чому б не використовувати контейнер IoC для вирішення залежностей для сутностей / бізнес-об’єктів?


82

Я розумію концепцію 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);
    }
}

Як бачите, залежності вводяться конструктором. Тепер на пару питань.

  1. Чи вважається поганою практикою, коли ваші сутності залежать від зовнішніх класів, таких як ShipQuoter? Усунення цих залежностей, здається, веде мене до анемічного домену, якщо я правильно розумію це визначення.

  2. Чи погана практика використовувати контейнер IoC для вирішення цих залежностей та побудови сутності за потреби? Чи можна це зробити?

Дякуємо за будь-яке розуміння.


3
просто робіть те, що вам потрібно, тому що це полегшує вам роботу, а не тому, що, мабуть, саме так ви повинні це робити
Ому

28
Як програміст-самоучка, я пішов цим шляхом, і це призвело до програмного забезпечення, яке в даний час використовується моєю компанією. Що з’явилося програмне забезпечення, засноване на процедурному сценарії / транзакції, частково тому, що воно було найпростішим та стороннім, оскільки я не знав нічого кращого. Абсолютно боляче підтримувати і розширювати, саме тому я витрачаю час, щоб переписати його, і шукаю поради у людей, які вже подолали ці проблеми, як не робити тих самих помилок.
Casey Wilkins

Відповіді:


90

На перше питання відповісти найважче. Чи погана практика, коли організації залежать від зовнішніх класів? Це, звичайно, не найпоширеніша справа.

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

Ви можете стверджувати, що ін'єкція інших залежностей в сутності призведе до того, що ви в тому ж напрямку (подалі від SRP). З іншого боку, ви, безумовно, праві, що якщо ви цього не зробите, тяга буде спрямована на Анемічну модель домену .

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

Переміщення нашого фокусу на моделюванні об’єктів домену як команд та подій замість іменників, схоже, дозволяє нам створити належну об’єктно-орієнтовану модель домену.

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


Дякую Марк. Я бачив Typed Factory і читав інші ваші дописи про метод Factory Factory, але ніколи не бачив прикладів їх використання для вирішення сутностей. Це тому, що більшість людей проектують свої сутності без будь-яких залежностей, окрім сховища? Чи потрапляю я в халепу, якщо жорстко використовую щось на зразок Typed Factory, щоб вирішити мої сутності, які мають зовнішні залежності?
Кейсі Уілкінс,

Справа в тому, що я намагався сказати, це те, що якщо ваші організації містять інших співавторів, які можуть отримати доступ до інших організацій тощо, ви можете зіткнутися з різними проблемами технічного обслуговування - не кажучи вже про порушення SRP та проблеми N + 1. Ось чому Еванс рекомендує розглядати кожну сутність як сукупний корінь.
Марк Сіманн

У моєму прикладі ShipQuoter визначає ціни доставки для замовлення від веб-служби (наприклад, ДБЖ). Ви б зробили цю Службу, яка приймає IOrder, або зробили б її частиною об'єкта домену, такого як Order.GetRates?
Кейсі Уілкінс

Я витратив би багато часу на те, щоб зрозуміти, як я міг уникнути синхронної тяги в першу чергу. Чим більше ви синхронно витягуєте дані, блокуючи, тим більш крихким стає ваш дизайн. Ось чому CQRS - це така приваблива альтернатива.
Mark Seemann

4
Ваше посилання на документ Грега мертве. Але він все ще доступний тут . І, схоже, це нова версія.
BornToCode

1

Я знаю, що це стара публікація, але хотів додати. Сутність домену не повинна зберігатися, навіть якщо ви переходите до абстрактного сховища в ctor. Причина, по якій я пропоную це, полягає не просто в тому, що він порушує SRP, а також суперечить агрегації DDD. Дозвольте мені пояснити, DDD підходить для складних додатків із глибинними по своїй суті графіками, тому ми використовуємо агреговані або складені корені, щоб продовжувати змінювати основні "діти", тому, коли ми вводимо наполегливість у окремих дітей, ми порушуємо відносини дітей до складений або сукупний корінь, який повинен «керувати» життєвим циклом або агрегацією. Звичайно, складений корінь або сукупність також не зберігаються на власному графіку. Інша ситуація з ін’єкційними залежностями об’єктів DDD полягає в тому, що ін’єктований об’єкт домену фактично не має стану, поки не відбудеться якась інша подія для гідратації його стану. Будь-який споживач коду буде змушений спершу ініціювати або налаштувати об’єкт домену, перш ніж він зможе викликати ділову поведінку, яка порушує інкапсуляцію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.