Внедрение зависимостей против фабричного шаблона

Большинство приведенных примеров использования внедрения зависимостей мы также можем решить, используя фабричный шаблон. Похоже, что когда дело доходит до использования / дизайна, разница между внедрением зависимостей и factory размыта или тонка.

Однажды кто-то сказал мне, что все зависит от того, как вы его используете!

Однажды я использовал StructureMap контейнер DI для решения проблемы, позже я переделал его для работы с простая фабрика и удаленные ссылки на StructureMap.

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


person Community    schedule 17.02.2009    source источник
comment
Разве эти два подхода не могут дополнять друг друга: использование внедрения зависимостей для внедрения фабричных классов?   -  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 просто упрощают задачу. - 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. Понятно. Ссылка вики en.wikipedia.org/wiki/ определяет шаблон фабрики как Manually-Injected Dependency - person gideon; 15.12.2010
comment
У меня нет преимущества изменения одной строки XML по сравнению с изменением одной строки кода. Не могли бы вы уточнить? - 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 против абстрактной фабрики. - person denis631; 04.09.2015
comment
Повторите ответ OP, заменив DI на factory, все еще имеет смысл. - 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 - один из способов реализации внедрения зависимостей. Еще одним преимуществом использования внедрения зависимостей в соответствии с шаблоном Factory является то, что DI Frameworks предоставят вам гибкость в том, как регистрировать ваши абстракции в соответствии с вашими конкретными типами. Например, код, такой как конфигурация, XML или автоконфигурация. Эта гибкость даст вам возможность управлять временем жизни ваших объектов или решать, как и когда регистрировать интерфейсы. - 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 от Миско Хевери потрясающий, и он является основой моего примера. 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. У них схожие цели, поскольку они стремятся отделить услуги от своих потребителей. Однако у шаблона 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

Причина, по которой внедрение зависимостей (DI) и заводские шаблоны схожи, заключается в том, что они представляют собой две реализации инверсии управления (IoC), которая представляет собой программную архитектуру. Проще говоря, это два решения одной и той же проблемы.

Итак, чтобы ответить на вопрос, основное различие между шаблоном Factory и DI заключается в том, как получается ссылка на объект. С внедрением зависимостей, поскольку название подразумевает, что ссылка вводится или передается вашему коду. При использовании шаблона Factory ваш код должен запрашивать ссылку, чтобы ваш код извлекал объект. Обе реализации удаляют или отделяют связь между кодом и базовым классом или типом ссылки на объект, используемой кодом.

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

Шаблон проектирования Factory довольно старый (с точки зрения программного обеспечения) и существует уже некоторое время. После недавней популярности архитектурного шаблона 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), и, с другой стороны, локатором служб или набором фабрик (factory):

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

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. Что мы хотим построить

Модуль приложения для создания заказа, который содержит несколько записей, называемый строкой заказа.

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

Предположим, мы хотим создать следующую архитектуру слоев:

введите описание изображения здесь

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

  1. Уровень домена и использование фабрик

Сущностями, которые будут в базе данных, являются Order и OrderLine. Заказ может иметь несколько строк заказа. «Связь

Теперь важная часть дизайна. Должны ли модули за пределами этого модуля создавать и управлять OrderLines самостоятельно? Нет. Строка заказа должна существовать, только если с ней связан заказ. Было бы лучше, если бы вы могли скрыть внутреннюю реализацию от внешних классов.

Но как создать Заказ, не зная о OrderLines?

Фабрика

Кто-то, кто хочет создать новый заказ, использовал OrderFactory (который скроет детали о том, как мы создаем Order).

введите описание изображения здесь

Вот так это будет выглядеть внутри 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
Объекты с отслеживанием состояния, скорее всего, будут на уровне домена приложения, где вы сопоставляете свои данные с базой данных, где вы обычно не используете внедрение зависимостей. Фабрика часто используется для создания AggregateRoot из дерева сложных объектов. - person Marcin Szymczak; 18.06.2017

Я считаю, что DI - это тип уровня абстракции на фабриках, но они также предоставляют преимущества, выходящие за рамки абстракции. Настоящая фабрика знает, как создать экземпляр одного типа и настроить его. Хороший уровень DI предоставляет возможность посредством конфигурации создавать экземпляры и настраивать многие типы.

Очевидно, что для проекта с несколькими простыми типами, для построения которого требуется относительно стабильная бизнес-логика, шаблон фабрики прост для понимания, реализации и хорошо работает.

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

person Community    schedule 17.02.2009

Я знаю, что это старый вопрос, но я хотел бы добавить свои пять центов,

Я думаю, что внедрение зависимостей (DI) во многом похоже на настраиваемый Factory Pattern (FP), и в этом смысле все, что вы могли бы сделать с DI, вы сможете сделать с помощью такой фабрики.

На самом деле, если вы используете, например, spring, у вас есть возможность автоматически подключать ресурсы (DI) или делать что-то вроде этого:

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

А затем используйте этот экземпляр «mb», чтобы делать что угодно. Разве это не вызов фабрики, которая вернет вам экземпляр ??

Единственная реальная разница, которую я замечаю между большинством примеров FP, заключается в том, что вы можете настроить, что "myBean" находится в xml или в другом классе, и фреймворк будет работать как фабрика, но в остальном это то же самое, и вы наверняка может иметь Factory, которая читает файл конфигурации или получает реализацию по мере необходимости.

И если вы спросите мое мнение (а я знаю, что вы этого не сделали), я считаю, что 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
Слишком многие разработчики думают, что фреймворки внедрения зависимостей созданы для того, чтобы привнести что-то новое. Как вы хорошо объяснили, традиционные фабрики (чаще всего абстрактные фабрики) могут играть ту же роль инверсии зависимостей. Инверсия против инъекции? Для меня единственное преимущество фреймворка Dependency Injection заключается в том, что нам не нужно изменять / перекомпилировать код (поскольку чаще всего настраивается с помощью XML, например Spring) при добавлении / изменении зависимости. Почему следует избегать перекомпиляции? Чтобы избежать возможных человеческих ошибок при изменении зависимости / factory. Но с нашими отличными IDE рефакторинг работает хорошо :) - person Mik378; 05.02.2013

IOC - это концепция, которая реализуется двумя способами. Создание зависимостей и внедрение зависимостей, Factory / Abstract factory являются примером создания зависимости. Внедрение зависимостей - это конструктор, установщик и интерфейс. Ядро IOC состоит в том, чтобы не зависеть от конкретных классов, а определять абстрактные методы (скажем, интерфейс / абстрактный класс) и использовать эту абстрактную информацию для вызова метода конкретного класса. Как и Factory, шаблон возвращает базовый класс или интерфейс. Подобное внедрение зависимостей использует базовый класс / интерфейс для установки значения для объектов.

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-компонентов. этот шаблон будет использоваться в основном, когда вам нужно создавать объекты с использованием шаблона проектирования фабрики, потому что при использовании этого шаблона вы не настраиваете свойства bean-компонента, а только создаете экземпляр объекта.

Проверьте эту ссылку: Внедрение зависимостей

person harshit    schedule 17.02.2009

Биной,

Я не думаю, что нужно выбирать одно вместо другого.

Акт перемещения зависимого класса или интерфейса в конструктор или установщик класса следует шаблону DI. Объект, который вы передаете конструктору или задаете, может быть реализован с помощью Factory.

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

person Jason Slocomb    schedule 17.02.2009

Я считаю, что три важных аспекта управляют объектами и их использованием:
1. Создание экземпляра (класса вместе с инициализацией, если таковая имеется).
2. Внедрение ( созданного таким образом экземпляра) там, где это требуется.
3. Управление жизненным циклом (созданного таким образом экземпляра).

При использовании шаблона Factory первым аспектом (создание экземпляра) является достигнуто, но оставшиеся два сомнительны. Класс, который использует другие экземпляры, должен жестко закодировать фабрики (вместо создания экземпляров), что препятствует возможности слабой связи. Более того, управление жизненным циклом экземпляров становится проблемой в большом приложении, где фабрика используется в нескольких местах (в частности, если фабрика не управляет жизненным циклом возвращаемого экземпляра, она получает уродливый).

С другой стороны, при использовании DI (шаблона IoC) все 3 абстрагируются вне кода (в контейнер DI), и управляемый компонент не нуждается в этой сложности. Свободное соединение, очень важная архитектурная цель может быть достигнута с комфортом. Еще одна важная архитектурная цель, разделение проблем, может быть достигнута намного лучше, чем фабрики.

В то время как фабрики могут подходить для небольших приложений, для крупных было бы лучше выбрать DI, а не фабрики.

person Community    schedule 28.04.2017

Мои мысли:

Внедрение зависимости: передайте соавторов в качестве параметров конструкторам. Платформа внедрения зависимостей: универсальная и настраиваемая фабрика для создания объектов, которые будут передаваться в качестве параметров конструкторам.

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

Фреймворк внедрения - это реализация фабричного паттерна.

Все зависит от ваших требований. Если вам нужно реализовать фабричный шаблон в приложении, весьма вероятно, что вашим требованиям будет удовлетворять одна из бесчисленных реализаций фреймворка внедрения.

Вам следует развертывать собственное решение только в том случае, если ваши требования не могут быть выполнены ни одной из сторонних фреймворков. Чем больше кода вы напишете, тем больше кода вам придется поддерживать. Код - это обязательство, а не актив.

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

person Community    schedule 17.06.2013

Заводской шаблон дизайна

Паттерн заводского проектирования характеризуется

  • Интерфейс
  • Классы реализации
  • Завод

Вы можете заметить несколько вещей, задав себе вопросы, как показано ниже.

  • Когда фабрика создаст объект для классов реализации - во время выполнения или во время компиляции?
  • Что, если вы хотите переключить реализацию во время выполнения? - Невозможно

Они обрабатываются внедрением зависимостей.

Внедрение зависимости

У вас могут быть разные способы внедрения зависимости. Для простоты давайте перейдем к внедрению интерфейса

В 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, Creation Pattern помогает создать нам объект - «Определить интерфейс для создания объекта». Если у нас есть объектный пул типа "ключ-значение" (например, словарь), передав ключ в Factory (я имею в виду простой шаблон Factory), вы можете разрешить тип. Работа сделана! С другой стороны, структура внедрения зависимостей (такая как 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 на 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 DI. DI должен быть невидимым.

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

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

GoF упоминает о сложности обновления абстрактных фабрик. Часть их объяснения цитируется в ответе здесь. Сравнение DI с фабриками также имеет много общего с вопросом Является ли ServiceLocator анти-шаблоном? < / а>

В конце концов, ответ на вопрос, какой выбрать, может быть неоднозначным; но я думаю, что все сводится к тому, что Factory является посредником. Вопрос в том, тянет ли этот посредник на себя, добавляя дополнительную ценность, помимо простой поставки продукта. Потому что, если вы можете получить тот же продукт без посредников, почему бы не исключить посредников?

Диаграмма помогает проиллюстрировать разницу. DI vs Factory

person Community    schedule 30.09.2020

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

Я использую Factory для создания различных объектов Layer (Business, Data Access).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

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

Эта структура уже называется Inversion Of Control. Я больше не несу ответственности за создание конкретного объекта. Но вам все равно нужно обеспечить внедрение зависимостей, чтобы можно было легко что-то изменить. Создание собственного пользовательского внедрения зависимостей - это нелепо, поэтому я использую Unity. В CreateCarBusiness () я прошу Unity решить, какой класс принадлежит к этому классу и какой у него срок жизни.

Итак, моя структура кода Factory Dependency Injection:

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

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

Я использую это, чтобы изменить доступ к данным базы данных на пользовательский уровень доступа к данным при создании модульных тестов. Я не хочу, чтобы мои модульные тесты взаимодействовали с базами данных, веб-серверами, серверами электронной почты и т. Д. Им нужно тестировать мой бизнес-уровень, потому что именно в этом и заключается интеллект.

person Community    schedule 25.06.2018

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

person Community    schedule 22.12.2014