Насправді, «правильний» спосіб - це взагалі НЕ використовувати завод, якщо немає іншого вибору (як при тестуванні одиниць та певних макетах - для виробничого коду ви НЕ використовуєте фабрику)! Це - насправді анти-модель, і її слід уникати будь-якою ціною. Вся справа в контейнері DI полягає в тому, щоб гаджет міг зробити роботу за вас.
Як було сказано вище в попередньому дописі, ви хочете, щоб ваш гаджет IoC взяв на себе відповідальність за створення різних залежних об'єктів у вашому додатку. Це означає, що дозволяти вашому гаджету DI створювати та керувати самими різними екземплярами. У цьому вся суть за DI - ваші об’єкти НІКОЛИ не повинні знати, як створювати та / або керувати об’єктами, від яких вони залежать. В іншому випадку розривається нещільна муфта.
Перетворення наявного додатка на всі DI - це величезний крок, але відміняючи очевидні труднощі при цьому, ви також хочете (лише полегшити своє життя), щоб вивчити інструмент DI, який виконає основну частину ваших прив’язок автоматично (Ядро до щось на зразок Ninject - це "kernel.Bind<someInterface>().To<someConcreteClass>()"
дзвінки, які ви робите, щоб відповідати оголошенням інтерфейсу тим конкретним класам, які ви хочете використовувати для реалізації цих інтерфейсів. Саме ті дзвінки "Прив'яжіть", які дозволяють вашому гаджету DI перехоплювати ваші виклики конструктора і надавати Для деяких класів типовим конструктором (псевдокодом, показаним тут) може бути:
public class SomeClass
{
private ISomeClassA _ClassA;
private ISomeOtherClassB _ClassB;
public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
{
if (aInstanceOfA == null)
throw new NullArgumentException();
if (aInstanceOfB == null)
throw new NullArgumentException();
_ClassA = aInstanceOfA;
_ClassB = aInstanceOfB;
}
public void DoSomething()
{
_ClassA.PerformSomeAction();
_ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
}
}
Зауважте, що ніде в цьому коді не було жодного коду, який створив / керував / випускав ні екземпляр SomeConcreteClassA, ні SomeOtherConcreteClassB. Власне кажучи, жоден конкретний клас навіть не посилався. Отже ... де трапилася магія?
У частині запуску вашої програми відбулося наступне (знову ж таки, це псевдокод, але він досить близький до реальної речі (Ninject) ...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
Цей маленький код там підказує гаджету Ninject шукати конструктори, сканувати їх, шукати екземпляри інтерфейсів, які він налаштований для обробки (це дзвінки "Прив’язати"), а потім створити та замінити екземпляр конкретного класу, де б не було на посилання на нього.
Є чудовий інструмент, який дуже добре доповнює Ninject під назвою Ninject.Extensions.Conventions (ще один пакет NuGet), який зробить основну частину цієї роботи за вас. Не відмовлятися від чудового досвіду навчання, який ви пройдете, будуючи це самостійно, але для того, щоб розпочати себе, це може бути інструментом для дослідження.
Якщо пам'ять служить, у Unity (формально від Microsoft зараз проект із відкритим кодом) є виклик методу або два, які роблять те саме, інші інструменти мають аналогічні помічники.
Який би шлях ви не вибрали, неодмінно прочитайте книгу Марка Семана для основної частини вашої підготовки до DI, однак, слід зазначити, що навіть "Великі" у світі інженерії програмного забезпечення (як Марк) можуть робити яскраві помилки - Марк забув про все Ninject у своїй книзі, ось ось ще один ресурс, написаний саме для Ninject. Я маю це і добре читаю: Освоєння нінжекту для введення в залежність