Инжектиране на зависимост срещу фабричен модел

Повечето от примерите, цитирани за използване на Dependency Injection, можем да решим и с помощта на фабричния шаблон. Изглежда, че когато става въпрос за използване/дизайн, разликата между инжектиране на зависимост и фабрика е замъглена или тънка.

Веднъж някой ми каза, че е важно как го използвате!

Веднъж използвах StructureMap DI контейнер за разрешаване на проблем, по-късно го препроектирах, за да работи с проста фабрика и премахнати препратки към StructureMap.

Може ли някой да ми каже каква е разликата между тях и къде какво да използвам, каква е най-добрата практика тук?


person Community    schedule 17.02.2009    source източник
comment
Не могат ли тези два подхода да се допълват взаимно: използване на Dependency Injection за инжектиране на фабрични класове?   -  person Richard Ev    schedule 23.12.2009
comment
Би било наистина хубаво, ако този въпрос имаше отговор с някакъв код! Все още не виждам как DI би било полезно/различно от използването на фабрика за създаване? Ще трябва само да замените този един ред във фабричния клас, за да промените кой обект/имплементация е създаден?   -  person gideon    schedule 14.12.2010
comment
@gideon няма ли това да ви принуди да компилирате приложението си или поне модула, съдържащ фабричния клас?   -  person lysergic-acid    schedule 28.04.2012
comment
@liortal да, точно така. Направих дълго проучване на DI след този коментар и сега разбирам, че DI взема фабричния метод една крачка напред.   -  person gideon    schedule 28.04.2012
comment
Вижте този страхотен отговор: stackoverflow.com/questions/4985455 / - той го формулира много добре и предоставя примерни кодове.   -  person Luis Perez    schedule 01.08.2012
comment
Виждали ли сте някога използване на инжектиране на зависимости, което не използва фабрики? Това би било странно, тъй като инжектирането на зависимост означава поставяне на кода за създаване на обект само на едно място, което налага цялата сложност/абстракция/досадни разходи на една фабрика. Няма ли да е глупаво да използваме DI, но не и фабрики?   -  person Phil Goetz    schedule 01.06.2015
comment
За да добавя моите два цента, ако някой се интересува как инжектирането на зависимост може да бъде полезно в темата за кафене, написах статия за това тук: digigene.com/design-patterns/dependency-injection-coffeeshop   -  person Ali Nem    schedule 07.11.2016
comment
Отговорът с най-много гласове няма смисъл. Фабричният модел на проектиране използва принципа на инверсия на зависимостта, който ИЗВЪРШВА екземпляр на код към друг клас. следователно отговорът му няма смисъл.   -  person Donato    schedule 21.03.2017
comment
IOC контейнер (като StructureMap) е просто фабрика за стероиди.   -  person ssmith    schedule 25.05.2017
comment
За да направите добро инжектиране на зависимости, трябва да разчитате на фабрики, това ви позволява да направите Composition Root, горно наслагване, което свързва всичките ви отделени компоненти заедно, отговаряйки на вашия случай на внедряване, можете да погледнете библиотеката на Di-Ninja, това е добър пример за изходен код за обяснение на целите на инжектирането на зависимости github.com/di-ninja/di-ninja   -  person DevTheJo    schedule 23.09.2018


Отговори (29)


Когато използвате фабрика, вашият код все още всъщност е отговорен за създаването на обекти. Чрез DI вие възлагате тази отговорност на друг клас или рамка, която е отделна от вашия код.

person willcodejavaforfood    schedule 17.02.2009
comment
Моделът DI не изисква никакви рамки. Можете да направите DI, като ръчно напишете фабрики, които правят DI. DI frameworks просто го улесняват. - person Esko Luontola; 17.02.2009
comment
@Perpetualcoder - Благодаря @Esko - Не се хващайте за думата рамка, която означава някаква усъвършенствана библиотека на трета страна. - person willcodejavaforfood; 17.02.2009
comment
Бихте ли казали какво е предимството да се даде на DI отговорността за създаване? В случай на фабричния метод трябва да промените един ред код там, за да промените коя реализация е създадена, нали? - person gideon; 14.12.2010
comment
@giddy - правилно, вече не е проблем с кода, а проблем с конфигурацията - person willcodejavaforfood; 15.12.2010
comment
+1 @willcode благодаря! Така че вместо това трябва да промените config/xml файловете. Виждам. Wiki връзката en.wikipedia.org/wiki/ дефинира фабричния модел като Manually-Injected Dependency - person gideon; 15.12.2010
comment
Не получавам предимството да променя 1 ред XML срещу промяна на 1 ред код. Бихте ли уточнили? - person Rafael Eyng; 19.03.2015
comment
@willcodejavaforfood, така че какъв е смисълът да се използва IoC вместо Abstract Factory? Тъй като когато нещо се промени в нашия код (например: добавена е нова зависимост), трябва да променим конфигурацията. Същият проблем имаме и с Abstract Factory. И така, както каза RafaelEyng, какво е предимството от промяната на 1 ред XML срещу промяната на 1 ред код? - person denis631; 01.09.2015
comment
@RafaelEyng единственото предимство, което виждам при използването на XML-config е: не е необходимо да компилирате отново, за да приложите промените. Но има и други методи за инжектиране на зависимости, които не използват XML като конфигурационен файл. В тези случаи не виждам никакво предимство от използването на IoC срещу Abstract Factory - person denis631; 04.09.2015
comment
Повторете отговора на OP, заменяйки DI с фабричен, все още има смисъл. - person Edson Medina; 09.12.2015
comment
Фабричният модел на проектиране използва принципа на инверсия на зависимостта, който ИЗВЪРШВА екземпляр на код към друг клас. следователно този отговор няма смисъл. - person Donato; 21.03.2017
comment
Няма смисъл произволно да считате фабрика за част от вашия код, докато произволно да смятате DI за отделен от вашия код. - person cowlinator; 01.12.2020

Бих предложил концепциите да бъдат ясни и прости. Инжектирането на зависимост е по-скоро архитектурен модел за слабо свързване на софтуерни компоненти. Фабричният шаблон е само един от начините за разделяне на отговорността за създаване на обекти от други класове към друг обект. Фабричният модел може да се нарече като инструмент за внедряване на DI. Инжектирането на зависимости може да се реализира по много начини като DI с помощта на конструктори, използване на картографиране на xml файлове и т.н.

person Perpetualcoder    schedule 17.02.2009
comment
Вярно е, че Factory Pattern е един от начините за прилагане на Dependency Injection. Друго предимство при използването на Dependency Injection срещу Factory Pattern е, че DI Frameworks ще ви даде гъвкавост за това как да регистрирате вашите абстракции спрямо вашите конкретни типове. Като код като Config, XML или Auto Configuration. Тази гъвкавост ще ви позволи да управлявате живота на вашите обекти или да решите как и кога да регистрирате вашите интерфейси. - person Teoman shipahi; 06.10.2014
comment
Фабричният шаблон предлага абстракция от по-високо ниво от DI. Една фабрика може да предложи опции за конфигурация точно както прави DI, но също така може да избере да скрие всички тези подробности за конфигурацията, така че фабриката да може да реши да премине към напълно различна реализация, без клиентът да знае. DI сама по себе си не позволява това. DI изисква от клиента да посочи промените, които иска. - person neuron; 02.04.2016
comment
Хубав отговор. Мнозина се объркват с този въпрос: Какви шарки да избера? Всъщност моделите на проектиране са просто начин за решаване на проблем в подходящи ситуации. Ако не знаете какъв шаблон за проектиране трябва да използвате или Къде трябва да внедря шаблона? тогава нямате нужда от това в момента. - person Benyi; 26.04.2018
comment
Мисля, че е по-точно да се каже, че Factory Pattern е инструмент за прилагане на IoC (не DI). Моля, имайте предвид, че DI е форма на IoC - person Hooman Bahreini; 29.10.2018
comment
@neuron, това е единственият случай на използване, при който ръчното внедряване на фабрика е оправдано, когато DI контейнер вече е наличен: когато искате да скриете подробностите за конфигурацията на създаването от повикващия. Освен това, DI контейнерът може идеално да служи като фабрика и да ви спести усилията за ръчно внедряване на такава. - person Lesair Valmont; 23.07.2020

Инжектиране на зависимост

Вместо да създава частите сама, колата пита за частите, от които се нуждае, за да функционира.

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

Фабрика

Сглобява частите заедно, за да направи цялостен обект и скрива конкретния тип от обаждащия се.

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

Резултат

Както можете да видите, Factories и DI се допълват взаимно.

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

Помните ли Златокоската и трите мечки? Е, инжектирането на зависимост е нещо подобно. Ето три начина да направите същото.

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

Пример #1 - Това е най-лошото, защото напълно скрива зависимостта. Ако гледате на метода като на черна кутия, няма да имате представа, че изисква кола.

Пример #2 - Това е малко по-добре, защото сега знаем, че имаме нужда от кола, тъй като минаваме през автомобилна фабрика. Но този път минаваме твърде много, тъй като всичко, от което методът всъщност се нуждае, е кола. Преминаваме през фабрика само за да построим колата, когато колата може да бъде построена извън метода и да бъде предадена.

Пример #3 - Това е идеално, защото методът изисква точно това, от което се нуждае. Нито твърде много, нито твърде малко. Не е нужно да пиша MockCarFactory само за да създам MockCars, мога да предам макета направо. Той е директен и интерфейсът не лъже.

Този Google Tech Talk от Misko Hevery е невероятен и е в основата на това, от което извлякох моя пример. http://www.youtube.com/watch?v=XcT4yYu_TTs

person Despertar    schedule 04.06.2013
comment
Фабричната схема се инжектира като DI. - person Mangesh Pimpalkar; 23.02.2014
comment
Понякога не знаете характеристиките на ICar предварително (като специални гуми, в зависимост от времето). В тези случаи ще отидете с #2 и ще инструктирате ICarFactory да разпръсне кола с този атрибут. Правят се много DI, защото няма разумен начин да изолирате вашите компоненти с тестване. #2 и #3 постигат това. - person PeerBr; 21.01.2015
comment
Това не е инжектиране на зависимости, това е просто предаване на зависимостите. Инжектирането на зависимости има само един клас, който знае какви са зависимостите, така че повикващият, който иска RaceCar, не трябва да знае, че изисква кола или carFactory. Скриването на зависимостта (както в пример 1) е /точката/ на инжектиране на зависимост. Не трябва да излага зависимости; трябва да съхранява кода, който ги предоставя, на едно място. - person Phil Goetz; 01.06.2015
comment
@PhilGoetz Това, което описвате, звучи повече като модела за локатор на услуги. Те имат подобни цели, тъй като се стремят да отделят услугите от техните потребители. Обаче има много недостатъци на модела Service Locator. Главно, скриването на зависимости не е добро нещо. Потребителят все още трябва да получи своите зависимости, но вместо да дефинира ясен интерфейс, те се предават „тайно“ и разчитат на глобално състояние. В примера потребителят няма представа за фабриката, той иска само това, от което се нуждае, и не трябва да се интересува от това как е конструирана тази нужда. - person Despertar; 02.06.2015
comment
Номер 1 не е проблемът да не знаете, че методът използва кола. Всъщност е валидна абстракция, когато вие като повикващия не се интересувате какво и как от метода, който извиквате. - person Matthew Whited; 03.08.2015
comment
@MatthewWhited Повечето дизайнерски решения имат компромис. С DI вие получавате гъвкавост, прозрачност и по-тестваема система, но с цената на излагане на вътрешностите ви. Много хора намират това за приемлив компромис. Това не означава, че DI винаги е най-доброто решение и този въпрос не е за това. Примерът има за цел да покаже разликата между DI и фабричен шаблон, като покаже някои добри и лоши употреби на всеки от тях. - person Despertar; 09.08.2015
comment
Това не е DI модел, това е просто реализация на IoC. DI използва ServiceLocator, за да определи правилната зависимост и да я инжектира в конструктора по време на създаването на обект, вашият код отделя само създаването на обекти от обхвата на вашия клас. - person Diego Mendes; 03.02.2016
comment
@DiegoMendes Това, което описвате, е рамка, която автоматизира DI. ServiceLocator, както го наричате, прави DI вместо вас. Това, което показвам, е самият модел, който не изисква никакви фантастични рамки. Вижте stackoverflow.com/a/140655/1160036 или вижте en.wikipedia.org/wiki/: [списък с рамки] поддържат инжектиране на зависимости, но не се изисква да правят инжектиране на зависимости. Също така, инжектирането е предаването на зависимост към зависим обект. Прекалявате да усложнявате една красиво проста концепция. - person Despertar; 03.02.2016
comment
Пример #3 - Това е идеално, защото методът иска точно това, от което се нуждае. Обикновено най-добрите методи просто извикват един метод вътре? Как може това да е идеално, когато е просто безсмислено. Това е проблемът с DI, хората просто прекарват повече време в писане на шаблонен код, а не в нещо полезно. - person Filip Cordas; 02.10.2016
comment
@FilipCordas Това е само пример за това как правилно да използвате DI, така че се фокусира върху интерфейса на метода, а не върху изпълнението. ICar може да бъде алгоритъм за криптиране или нещо, което запазва данните. Това са само две от хилядите неща, за които може да не искате да кодирате твърди класове. DI има компромиси като всички неща, така че трябва да използвате най-добрата си преценка кога гъвкавостта, която получавате, си струва косвеността и т.н. - person Despertar; 04.12.2016
comment
@Despertar Да, може, но не става. Проблемът ми, когато говоря за DI, е, че хората говорят така, сякаш това решава всички проблеми във всяка ситуация, дори когато би било по-добри решения за същата ситуация, както в примера, който дадохте. И моделът на ServiceLocator не е DI шаблон, и двата са IOC шаблони, но двата са различни. - person Filip Cordas; 05.12.2016

Причината, поради която Dependency Injection (DI) и Factory Patterns са сходни, е, че те са две реализации на Inversion of Control (IoC), което е софтуерна архитектура. Казано просто, това са две решения на един и същи проблем.

Така че, за да отговоря на въпроса, основната разлика между модела Factory и DI е как се получава препратката към обекта. С инжектиране на зависимости, както подсказва името, препратката се инжектира или дава на вашия код. С Factory pattern вашият код трябва да поиска препратката, така че вашият код да извлече обекта. И двете реализации премахват или разединяват връзката между кода и основния клас или тип на препратката към обект, използван от кода.

Струва си да се отбележи, че Factory шаблоните (или всъщност Abstract Factory шаблоните, които са фабрики, които връщат нови фабрики, които връщат препратки към обекти) могат да бъдат написани за динамичен избор или връзка към типа или класа на обекта, който се изисква по време на изпълнение. Това ги прави много подобни (дори повече от DI) на модела Service Locator, който е друга реализация на IoC.

Фабричният дизайнерски модел е доста стар (по отношение на софтуера) и съществува от известно време. След неотдавнашната популярност на архитектурния модел IoC той се възражда.

Предполагам, че когато става дума за модели на проектиране на IoC: инжекторите инжектират, локаторите локализират и фабриките са преработени.

person Community    schedule 13.03.2014
comment
Това е най-добрият отговор... другите отговори или не споменават IoC, или не признават, че DI е форма на IoC. - person Hooman Bahreini; 29.10.2018
comment
Благодаря, когато за първи път изучавах IOC, почти изкрещях, че това е просто друга форма на фабричния модел, оказа се, че те наистина са подобни един на друг - person Harvey Lin; 23.07.2019

Има проблеми, които са лесни за решаване с инжектиране на зависимости, които не се решават толкова лесно с набор от фабрики.

Някои от разликите между, от една страна, инверсия на управление и инжектиране на зависимост (IOC/DI) и, от друга страна, локатор на услуга или набор от фабрики (фабрика), е:

IOC/DI е пълна екосистема от домейн обекти и услуги сама по себе си. Той настройва всичко за вас по начина, който посочите. Обектите и услугите на вашия домейн са конструирани от контейнера и не се конструират сами: следователно те нямат никакви зависимости от контейнера или от каквито и да е фабрики. IOC/DI позволява изключително висока степен на конфигурируемост, като цялата конфигурация е на едно място (конструкция на контейнера) на най-горния слой на вашето приложение (GUI, уеб интерфейс).

Factory абстрахира някои от конструкцията на обектите и услугите на вашия домейн. Но обектите и услугите на домейна все още са отговорни за това как да се конструират и как да получат всички неща, от които зависят. Всички тези „активни“ зависимости филтрират целия път през всички слоеве във вашето приложение. Няма едно място, където да отидете, за да конфигурирате всичко.

person yfeldblum    schedule 17.02.2009

Един недостатък на DI е, че не може да инициализира обекти с логика. Например, когато трябва да създам герой с произволно име и възраст, DI не е изборът пред фабричния модел. С фабриките можем лесно да капсулираме произволния алгоритъм от създаването на обект, който поддържа един от моделите на проектиране, наречен „Енкапсулиране на това, което варира“.

person Community    schedule 01.05.2012

Управлението на жизнения цикъл е една от отговорностите, които контейнерите за зависимости поемат в допълнение към инстанцирането и инжектирането. Фактът, че контейнерът понякога запазва препратка към компонентите след инстанциране, е причината да се нарича "контейнер", а не фабрика. Контейнерите за инжектиране на зависимости обикновено поддържат само препратка към обекти, които са му необходими за управление на жизнените цикли, или които се използват повторно за бъдещи инжекции, като сингълтони или летви. Когато е конфигуриран да създава нови екземпляри на някои компоненти за всяко извикване на контейнера, контейнерът обикновено просто забравя за създадения обект.

От: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html

person Community    schedule 20.12.2010

Теория

Има два важни момента, които трябва да имате предвид:

  1. Който създава предмети

    • [Factory]: You have to write HOW object should be created. You have separate Factory class which contains creation logic.
    • [Инжектиране на зависимост]: В практическите случаи се извършва от външни рамки (например в Java това би било spring/ejb/guice). Инжектирането се случва "магически" без изрично създаване на нови обекти
  2. Какви обекти управлява:

    • [Factory]: Usually responsible for creation of stateful objects
    • [Инжектиране на зависимости] По-вероятно е да се създадат обекти без състояние

Практически пример как да използвате както фабрично, така и инжектиране на зависимости в един проект

  1. Какво искаме да изградим

Приложен модул за създаване на поръчка, която съдържа множество записи, наречена orderline.

  1. Архитектура

Да приемем, че искаме да създадем следната архитектура на слоя:

въведете описание на изображението тук

Обектите на домейна могат да бъдат обекти, съхранявани в база данни. Хранилище (DAO) помага при извличане на обекти от база данни. Услугата предоставя API на други модули. Позволява операции на order модул

  1. Слой на домейн и използване на фабрики

Обектите, които ще бъдат в базата данни, са Order и OrderLine. Поръчката може да има няколко OrderLines. „Връзка

Сега идва важната част от дизайна. Трябва ли модули извън този да създават и управляват OrderLines сами? Не. Линията за поръчка трябва да съществува само когато имате поръчка, свързана с нея. Би било най-добре, ако можете да скриете вътрешната имплементация за външни класове.

Но как да създадете Order без знания за OrderLines?

Фабрика

Някой, който иска да създаде нова поръчка, използва OrderFactory (която ще скрие подробности за това как създаваме поръчка).

въведете описание на изображението тук

Така ще изглежда в IDE. Класовете извън пакета domain ще използват OrderFactory вместо конструктор вътре в Order

  1. Инжектиране на зависимост Инжектирането на зависимост се използва по-често със слоеве без състояние, като хранилище и услуга.

OrderRepository и OrderService се управляват от рамка за инжектиране на зависимости. Хранилището е отговорно за управлението на CRUD операции в база данни. Услугата инжектира хранилище и го използва за запазване/намиране на правилни класове домейн.

въведете описание на изображението тук

person Community    schedule 29.05.2017
comment
Можете ли да изясните това? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objects Не разбирам защо - person Maksim Dmitriev; 18.06.2017
comment
Обектите с поддържане на състоянието вероятно ще бъдат в слоя на домейна на приложението, където картографирате вашите данни към база данни, където обикновено не използвате инжектиране на зависимости. Factory се използва често за създаване на AggregateRoot от дърво от сложни обекти - person Marcin Szymczak; 18.06.2017

Вярвам, че DI е вид абстракционен слой във фабриките, но те също така осигуряват предимства извън абстракцията. Истинската фабрика знае как да създаде единичен тип и да го конфигурира. Един добър DI слой предоставя възможност чрез конфигуриране да се създават и конфигурират много типове.

Очевидно за проект с няколко прости типа, който изисква относително стабилна бизнес логика в тяхното изграждане, фабричният модел е лесен за разбиране, прилагане и работи добре.

OTOH, ако имате проект, съдържащ множество типове, чиито реализации очаквате да се променят често, DI ви дава гъвкавостта чрез своята конфигурация, за да правите това по време на изпълнение, без да се налага да компилирате повторно вашите фабрики.

person Community    schedule 17.02.2009

Знам, че този въпрос е стар, но бих искал да добавя моите пет цента,

Мисля, че инжектирането на зависимости (DI) е в много отношения като конфигурируем фабричен модел (FP) и в този смисъл всичко, което можете да направите с DI, ще можете да го направите с такава фабрика.

Всъщност, ако използвате spring например, имате възможност за автоматично свързване на ресурси (DI) или да направите нещо подобно:

MyBean mb = ctx.getBean("myBean");

И след това използвайте този екземпляр „mb“, за да направите каквото и да било. Това не е ли обаждане до фабрика, която ще ти върне екземпляр??

Единствената реална разлика, която забелязвам между повечето FP примери е, че можете да конфигурирате какво е "myBean" в xml или в друг клас и рамката ще работи като фабрика, но освен това е едно и също нещо и вие със сигурност може да има фабрика, която чете конфигурационен файл или получава изпълнението според нуждите си.

И ако ме попитате за моето мнение (и знам, че не сте го направили), аз вярвам, че DI прави същото, но само добавя повече сложност към разработката, защо?

добре, от една страна, за да знаете каква е имплементацията, използвана за всеки bean, който свързвате автоматично с DI, трябва да отидете до самата конфигурация.

но... какво ще кажете за това обещание, че няма да се налага да знаете изпълнението на обекта, който използвате? пффт! сериозно? когато използвате подход като този... не сте ли същият, който пише изпълнението?? и дори да не го направите, не гледате ли почти през цялото време как изпълнението прави това, което трябва да прави??

и за последно нещо, няма значение колко много ви обещава една DI рамка, че ще изградите неща отделени от нея, без зависимости от техните класове, ако използвате рамка, вие изграждате всичко около нея, ако трябва да промените подхода или рамката, това няма да е лесна задача... НИКОГА!... но тъй като изграждате всичко около това конкретна рамка, вместо да се тревожите кое е най-доброто решение за вашия бизнес, тогава ще се сблъскате с огромен проблем, когато правите това.

Всъщност единственото реално бизнес приложение за FP или DI подход, което виждам, е ако трябва да промените реализациите, използвани по време на изпълнение, но поне рамките, които познавам, не ви позволяват направете това, трябва да оставите всичко перфектно в конфигурацията по време на разработка и ако имате нужда от това, използвайте друг подход.

Така че, ако имам клас, който се представя по различен начин в два обхвата в едно и също приложение (да речем, две компании от холдинг), трябва да конфигурирам рамката, за да създам два различни зърна, и да адаптирам кода си, за да използва всеки от тях. Не е ли същото като ако просто напиша нещо подобно:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

същото като това:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

И този:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

Във всеки случай ще трябва да промените нещо във вашето приложение, независимо дали класове или конфигурационни файлове, но ще трябва да го направите, като го преразпределите.

Не би ли било хубаво да направим нещо подобно:

MyBean mb = (MyBean)MyFactory.get("mb"); 

И по този начин вие задавате кода на фабриката, за да получите правилната реализация по време на изпълнение в зависимост от вписаното потребителско предприятие?? Сега ТОВА би било полезно. Можете просто да добавите нов буркан с новите класове и да зададете правилата може би дори по време на изпълнение (или да добавите нов конфигурационен файл, ако оставите тази опция отворена), без промени в съществуващите класове. Това ще бъде динамична фабрика!

няма ли да е по-полезно, отколкото да се налага да пишете две конфигурации за всяко предприятие и може би дори да имате две различни приложения за всяко??

Можете да ми кажете, че никога не е необходимо да правя превключване по време на изпълнение, така че конфигурирам приложението и ако наследя класа или използвам друга реализация, просто променям конфигурацията и преразпределям. Добре, това може да се направи и с фабрика. И бъди честен, колко пъти правиш това? може би само когато имате приложение, което ще се използва някъде другаде във вашата компания, и вие ще предадете кода на друг екип и те ще правят неща като тези. Но хей, това може да се направи и с фабриката и би било още по-добре с динамична фабрика!!

Както и да е, разделът за коментари е отворен, за да ме убиете.

person Community    schedule 13.09.2012
comment
Твърде много разработчици смятат, че рамките за инжектиране на зависимости са създадени, за да донесат нещо ново. Както добре обяснявате, традиционните фабрики (най-често абстрактна фабрика) могат да играят същата роля на инверсия на зависимости. Инверсия срещу инжектиране? За мен единственото предимство на рамката за инжектиране на зависимости е, че не трябва да променяме/прекомпилираме кода (тъй като най-често се конфигурира с XML като Spring), когато се добавя/променя зависимост. Защо да избягвате прекомпилирането? За да се избегнат някои потенциални човешки грешки при промяна на зависимост/фабрика. Но с нашите страхотни IDE, рефакторингът работи добре :) - person Mik378; 05.02.2013

IOC е концепция, която се реализира по два начина. Създаване на зависимост и инжектиране на зависимост, Factory/Abstract factory са пример за създаване на зависимост. Инжектирането на зависимости е конструктор, сетер и интерфейс. Ядрото на IOC е да не зависи от конкретните класове, а да дефинира абстрактното на методите (да речем интерфейс/абстрактен клас) и да използва това абстрактно за извикване на метод на конкретен клас. Подобно на Factory pattern връща базовия клас или интерфейс. По подобен начин инжектирането на зависимости използва базов клас/интерфейс за задаване на стойност за обекти.

person Community    schedule 28.08.2011

С инжектирането на зависимости клиентът не трябва да получава своите зависимости сам, всичко е подготвено предварително.

При фабриките някой трябва да ги извика, за да пренесе генерираните обекти до мястото, където са необходими.

Разликата се състои най-вече в този един ред, където се извършва извикването на фабриката и извличането на конструирания обект.

Но с фабриките трябва да напишете този 1 ред навсякъде, където имате нужда от такъв обект. С DI просто трябва да създадете окабеляването (връзката между употребата и създадения обект) веднъж и просто да разчитате на присъствието на обекта след това навсякъде. От друга страна, DI често изисква малко повече (колко зависи от рамката) работа по подготовката.

person Kosi2801    schedule 17.02.2009

Имах същия въпрос, веднага щом прочетох за DI и стигнах до тази публикация. Така че най-накрая това е, което разбрах, но моля, поправете ме, ако греша.

„Преди много време е имало малки кралства със собствени управителни органи, контролиращи и вземащи решения въз основа на собствени писмени правила. По-късно сформирано голямо правителство, премахващо всички тези малки управителни органи, което има един набор от правила (конституция) и се прилага чрез съдилища“

Управителните органи на малките кралства са "Фабрики"

Голямото правителство е „инжекторът на зависимости“.

person Community    schedule 20.12.2010
comment
И така, КОГА едно предишно малко правителство ще стане голямо? С каква мярка? - person Prisoner ZERO; 22.11.2011


Повечето отговори тук обясняват концептуалната разлика и подробностите за изпълнението на двете. Въпреки това не можах да намеря обяснение за разликата в приложението кое IMO е най-важното и OP попита. Така че да отворя тази тема отново...

Веднъж някой ми каза, че е важно как го използвате!

Точно. В 90% от случаите можете да получите препратка към обект, като използвате Factory или DI и обикновено завършвате с последния. В други 10% от случаите използването на Factory е единственият правилен начин. Тези случаи включват получаване на обекти чрез променлива по време на изпълнение на параметри. Като този:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

В този случай получаването на client от DI не е възможно (или поне изисква някакво грозно решение). Така че като общо правило за вземане на решение: ако зависимост може да бъде получена без изчислени параметри по време на изпълнение, тогава се предпочита DI, в противен случай използвайте Factory.

person Community    schedule 21.11.2017

С фабрика можете да групирате свързани интерфейси, така че ако предадените параметри могат да бъдат групирани във фабрика, това също е добро решение за constructor overinjection погледнете този код *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Погледнете конструктора, трябва само да подадете IAddressModelFactory там, така че по-малко параметри *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

Виждате в CustomerController много предадени параметри, Да, можете да видите това като constructor overinjection, но това е начинът, по който работи DI. И не, нищо не е наред с CustomerController.

*) Кодът е от nopCommerce.

person Community    schedule 28.11.2017

С прости думи Инжектиране на зависимост срещу Фабричен метод предполага съответно механизъм натискане срещу изтегляне.

Механизъм за изтегляне: класът индиректно има зависимост от фабричния метод, който от своя страна зависи от конкретни класове.

Механизъм за натискане: Основният компонент може да бъде конфигуриран с всички зависими компоненти на едно място и по този начин насърчава високата поддръжка и хлабавото свързване.

При метода Factory отговорността все още е на класа (макар и косвено) за създаване на нов обект, където, както при инжектирането на зависимости, тази отговорност е възложена на външни изпълнители (все пак с цената на изтичане на абстракция)

person Community    schedule 13.02.2018
comment
@RahulAgarwal, какво означава последната част, все пак с цената на изтичане на абстракция? DI пропуска абстракция по начин, по който Factory не го прави? - person jaco0646; 12.11.2020

вярвам, че DI е начин за конфигуриране или инстанциране на bean. DI може да се направи по много начини като конструктор, сетер-гетер и т.н.

Фабричният модел е просто друг начин за инстанциране на зърна. този модел ще се използва главно, когато трябва да създавате обекти, използвайки фабричен шаблон за проектиране, тъй като докато използвате този шаблон, вие не конфигурирате свойствата на bean, а само инстанциирате обекта.

Проверете тази връзка: Инжектиране на зависимост

person harshit    schedule 17.02.2009

Бинодж,

Не мисля, че трябва да избираш едно пред друго.

Актът на преместване на зависим клас или интерфейс към конструктор или сетер на клас следва модела DI. Обектът, който предавате на конструктора или набора, може да бъде имплементиран с Factory.

Кога да се използва? Използвайте шаблона или шаблоните, които се намират в рулевата рубка на вашия разработчик. С какво се чувстват най-комфортно и най-лесно за разбиране.

person Jason Slocomb    schedule 17.02.2009

Вярвам, че 3 важни аспекта управляват обектите и тяхната употреба:
1. Инстанциране (на клас заедно с инициализация, ако има такава).
2. Инжектиране ( на така създадения екземпляр), където се изисква.
3. Управление на жизнения цикъл (на така създадения екземпляр).

Използвайки Factory шаблон, първият аспект (инстанция) е постигнато, но останалите две са под въпрос. Класът, който използва други екземпляри, трябва да твърдо кодира фабриките (вместо да се създават екземпляри), което възпрепятства възможностите за слабо свързване. Освен това, управлението на жизнения цикъл на екземплярите се превръща в предизвикателство в голямо приложение, където една фабрика се използва на множество места (по-специално, ако фабриката не управлява жизнения цикъл на екземпляра, който връща, получава грозен).

Използвайки DI (на IoC модел) от друга страна, всичките 3 се абстрахират извън кода (към DI контейнера) и управляваният bean не се нуждае от нищо относно тази сложност. Слабо свързване, една много важна архитектурна цел може да бъде постигната тихо и комфортно. Друга важна архитектурна цел, разделянето на концерните може да бъде постигнато много по-добре от фабриките.

Докато фабриките може да са подходящи за малки приложения, големите би било по-добре да изберат DI пред фабриките.

person Community    schedule 28.04.2017

Мислите ми:

Инжектиране на зависимости: предавайте сътрудници като параметри на конструкторите. Dependency Injection Framework: обща и конфигурируема фабрика за създаване на обекти, които да се предават като параметри на конструкторите.

person Community    schedule 28.10.2009
comment
Да точно. Почти всички споменавания на Инжектиране на зависимост (DI) в тези въпроси и отговори злоупотребяват с термина в контраст с това определение. Контейнерът за инжектиране на зависимости (DIC) е най-често срещаната рамка, действаща като обща и конфигурируема фабрика за създаване на обекти. - person CXJ; 14.04.2017

Рамката за инжектиране е реализация на фабричния модел.

Всичко зависи от вашите изисквания. Ако трябва да внедрите фабричния модел в приложение, много вероятно е вашите изисквания да бъдат изпълнени от едно от безбройните внедрявания на рамка за инжектиране.

Трябва да внедрите свое собствено решение само ако вашите изисквания не могат да бъдат изпълнени от никоя от рамките на трета страна. Колкото повече код пишете, толкова повече код трябва да поддържате. Кодът е пасив, а не актив.

Аргументите за това коя реализация трябва да използвате не са толкова фундаментално важни, колкото разбирането на архитектурните нужди на вашето приложение.

person Community    schedule 17.06.2013

Фабричен модел на дизайн

Фабричният модел на проектиране се характеризира с

  • Интерфейс
  • Класове за внедряване
  • Фабрика

Можете да забележите няколко неща, когато се запитате по-долу

  • Кога фабриката ще създаде обект за класовете за изпълнение - по време на изпълнение или време за компилиране?
  • Ами ако искате да превключите изпълнението по време на изпълнение? - Не е възможно

Те се обработват чрез инжектиране на зависимости.

Инжектиране на зависимост

Можете да имате различни начини, по които можете да инжектирате зависимост. За по-лесно нека да преминем към Interface Injection

В DI контейнерът създава необходимите екземпляри и ги "инжектира" в обекта.

По този начин елиминира статичното инстанциране.

Пример:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}
person Community    schedule 24.09.2014

От номинална стойност изглеждат еднакви

С много прости думи, Factory Pattern, Creational Pattern ни помага да създадем обект - „Дефиниране на интерфейс за създаване на обект“. Ако имаме набор от обекти с ключова стойност (напр. речник), предавайки ключа на фабриката (имам предвид простия фабричен шаблон), можете да разрешите типа. Работата свършена! Рамката за инжектиране на зависимости (като Structure Map, Ninject, Unity ... и т.н.) от друга страна изглежда прави същото.

Но... „Не преоткривайте колелото“

От архитектурна гледна точка това е обвързващ слой и „не преоткривайте колелото“.

За корпоративно приложение концепцията за DI е по-скоро архитектурен слой, който дефинира зависимости. За да опростите това допълнително, можете да мислите за това като за отделен проект на класова библиотека, който прави разрешаване на зависимости. Основното приложение зависи от този проект, където Резолверът на зависимости се отнася до други конкретни реализации и към разрешаването на зависимости.

В допълнение към "GetType/Create" от Factory, най-често се нуждаем от повече функции (възможност за използване на XML за дефиниране на зависимости, подигравки и тестване на единици и т.н.). Тъй като споменахте Структурна карта, погледнете списък с функции на Структурна карта . Очевидно е повече от просто решаване на просто картографиране на обекти. Не преоткривайте колелото!

Ако всичко, което имате, е чук, всичко изглежда като пирон

В зависимост от вашите изисквания и какъв тип приложение създавате, трябва да направите избор. Ако има само няколко проекта (може да са един или два...) и включва малко зависимости, можете да изберете по-прост подход. Това е като да използвате ADO .Net достъп до данни вместо да използвате Entity Framework за прости 1 или 2 извиквания на база данни, където въвеждането на EF е излишно в този сценарий.

Но за по-голям проект или ако вашият проект стане по-голям, силно бих препоръчал да имате DI слой с рамка и да освободите място за промяна на DI рамката, която използвате (Използвайте фасада в основното приложение (уеб приложение, уеб API, десктоп) ..и т.н.).

person Community    schedule 31.03.2016

Мисля, че те са ортогонални и могат да се използват заедно. Нека ви покажа един пример, на който наскоро попаднах на работа:

Използвахме Spring framework в Java за DI. Единичен клас (Parent) трябваше да инстанцира нови обекти от друг клас (Child), а те имаха сложни сътрудници:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

В този пример Parent трябва да получи DepX екземпляри само за да ги предаде на конструктора Child. Проблеми с това:

  1. Parent има повече познания за Child отколкото трябва
  2. Parent има повече сътрудници, отколкото трябва
  3. Добавянето на зависимости към Child включва промяна на Parent

Тогава разбрах, че Factory ще пасне идеално тук:

  1. Той скрива всички освен истинските параметри на класа Child, както се вижда от Parent
  2. Той капсулира знанията за създаване на Child, който може да бъде централизиран в конфигурацията на DI.

Това е опростеният клас Parent и класът ChildFactory:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}
person Community    schedule 16.04.2018

Използвате инжектиране на зависимости, когато знаете точно какъв тип обекти имате нужда в този момент. Докато в случай на фабричен модел, вие просто делегирате процеса на създаване на обекти на фабриката, тъй като не сте наясно какъв точно тип обекти имате нужда.

person Community    schedule 04.05.2020

DI ви дава композиционен корен , което е едно централизирано място за свързване на вашата обектна графика. Това има тенденция да прави зависимостите на обектите много ясни, защото обектите искат точно това, от което се нуждаят, и има само едно място да го получат.

Композиционният корен е чисто и ясно разделяне на проблемите. Обектите, които се инжектират, не трябва да зависят от DI механизма, независимо дали това е контейнер на трета страна или DIY DIY. DI трябва да е невидим.

Фабриките са склонни да бъдат по-разпределени. Различните обекти използват различни фабрики и фабриките представляват допълнителен слой на индиректност между обектите и техните действителни зависимости. Този допълнителен слой добавя свои собствени зависимости към обектната графика. Фабриките не са невидими. Фабриката е посредник.

Поради тази причина актуализирането на фабрики е по-проблематично: тъй като фабриките са зависимост от бизнес логиката, модифицирането им може да има вълнообразен ефект. Коренът на композицията не е зависимост от бизнес логиката, така че може да бъде модифициран изолирано.

GoF споменава трудността при актуализирането на абстрактните фабрики. Част от тяхното обяснение е цитирано в отговор тук. Контрастирането на DI с Factories също има много общо с въпроса, ServiceLocator анти-модел ли е?

В крайна сметка отговорът кой да изберете може да бъде самоуверен; но мисля, че се свежда до това, че фабриката е посредник. Въпросът е дали този посредник дърпа тежестта си, като добавя допълнителна стойност отвъд простото доставяне на продукт. Защото, ако можете да получите същия продукт без посредник, тогава защо да не премахнете посредника?

Една диаграма помага да се илюстрира разликата. DI срещу фабрика

person Community    schedule 30.09.2020

Използвам и двете, за да създам стратегия за инверсия на контрола с по-голяма четливост за разработчиците, които трябва да я поддържат след мен.

Използвам фабрика, за да създам моите различни обекти на слой (бизнес, достъп до данни).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Друг разработчик ще види това и когато създава обект на бизнес слой, той разглежда в BusinessFactory и Intellisense дава на разработчика всички възможни бизнес слоеве за създаване. Не е нужно да играя играта, намерете интерфейса, който искам да създам.

Тази структура вече е инверсия на контрола. Вече не нося отговорност за създаването на конкретния обект. Но все пак трябва да осигурите инжектиране на зависимост, за да можете лесно да променяте нещата. Създаването на собствено персонализирано инжектиране на зависимости е абсурдно, затова използвам Unity. В рамките на CreateCarBusiness() питам Unity да реши кой клас принадлежи към това и е доживотен.

Така че моята структура на Factory Dependency Injection на кода е:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

Сега имам полза и от двете. Моят код също е по-четлив за други разработчици по отношение на обхватите на моите обекти, които използвам, вместо Constructor Dependency Injection, което просто казва, че всеки обект е наличен, когато класът е създаден.

Използвам това, за да променя достъпа си до база данни с персонализиран кодиран слой за достъп до данни, когато създавам Unit Tests. Не искам моите модулни тестове да комуникират с бази данни, уеб сървъри, сървъри за електронна поща и т.н. Те трябва да тестват моя бизнес слой, защото там е интелигентността.

person Community    schedule 25.06.2018

Използването на инжектиране на зависимости е много по-добро по мое мнение, ако: 1. разполагате кода си в малък дял, защото се справя добре с отделянето на един голям код. 2. Тестваемостта е един от случаите, в които DI е добре да се използва, защото можете лесно да се подигравате на несвързаните обекти. с помощта на интерфейси можете лесно да се подигравате и тествате всеки обект. 3. можете едновременно да ревизирате всяка част от програмата, без да е необходимо да кодирате другата част от нея, тъй като тя е свободно отделена.

person Community    schedule 22.12.2014