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

498

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

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

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

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

Binoj Antony
источник
22
Разве эти два подхода не могут дополнять друг друга: использование Dependency Injection для внедрения фабричных классов?
Ричард Эв
20
Было бы здорово, если бы на этот вопрос был ответ с кодом! Я до сих пор не понимаю, как DI будет выгодно / отличается от использования фабрики для создания? Вам нужно будет только заменить эту одну строку в классе фабрики, чтобы изменить, какой объект / реализацию создается?
Гидеон
2
@gideon это не заставит вас скомпилировать ваше приложение или хотя бы модуль, содержащий фабричный класс?
лизергиновая кислота
1
@liortal Да, верно. После этого комментария я долго изучал DI, и теперь я понимаю, что DI продвигает фабричный метод на шаг впереди.
Гидеон
1
Посмотрите на этот замечательный ответ: stackoverflow.com/questions/4985455/… - он очень хорошо это произносит и предоставляет примеры кода.
Луис Перес

Ответы:

294

При использовании фабрики ваш код по-прежнему фактически отвечает за создание объектов. Используя DI, вы передаете эту ответственность другому классу или фреймворку, который отделен от вашего кода.

willcodejavaforfood
источник
172
Шаблон DI не требует никаких структур. Вы можете сделать DI, написав вручную фабрики, которые делают DI. DI рамки просто делают это проще.
Эско Луонтола
28
@Perpetualcoder - Спасибо @Esko - Не увлекайтесь структурой слова, означающей некоторую продвинутую стороннюю библиотеку.
willcodejavaforfood
4
+1 @Willcode спасибо! Так что вместо этого вы должны изменить файлы config / xml. Понимаю. Ссылка на вики en.wikipedia.org/wiki/… определяет шаблон фабрики какManually-Injected Dependency
gideon
5
Я не получаю преимущество изменения 1 строки XML по сравнению с изменением 1 строки кода. Не могли бы вы уточнить?
Рафаэль Эйнг
1
Повторите ответ OP, заменив «DI» на «заводской», все еще имеет смысл.
Эдсон Медина
219

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

Perpetualcoder
источник
4
Это правда, что Factory Pattern - один из способов внедрения Dependency Injection. Другое преимущество использования Dependency Injection против Factory Pattern заключается в том, что DI Frameworks даст вам гибкость в том, как зарегистрировать ваши абстракции для ваших конкретных типов. Такие как код как Config, XML или автоконфигурация. Такая гибкость позволит вам управлять временем жизни ваших объектов или решать, как и когда регистрировать ваши интерфейсы.
Теоман Шипахи
1
Фабричный шаблон предлагает более высокий уровень абстракции, чем DI. Фабрика может предлагать параметры конфигурации точно так же, как DI, но она также может скрыть все эти детали конфигурации, чтобы фабрика могла принять решение о переходе на совершенно другую реализацию без ведома клиента. Д.И. сам по себе не позволяет этого. DI требует от клиента указать изменения, которые он хочет.
Нейрон
1
Хороший ответ. Многие путают с этим вопросом: «Какие паттерны мне выбрать?» Фактически, шаблоны проектирования - это просто способ решения проблемы в соответствующих ситуациях. Если вы не знаете, какой шаблон проектирования вы должны использовать, или «Где я должен реализовать шаблон?» тогда тебе это не нужно.
Benyi
2
Я думаю, что точнее будет сказать, что Factory Pattern - это инструмент для реализации IoC (не DI). Обратите внимание, что DI является формой IoC
Hooman Bahreini
185

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

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

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;
    }   
}

Результат

Как видите, фабрики и 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

Деспертар
источник
1
Заводская модель вводится как DI.
Мангеш Пимпалкар
7
@PhilGoetz То, что вы описываете, больше похоже на шаблон Service Locator. У них схожие цели в том, что они стремятся отделить услуги от своих потребителей. Однако у шаблона Service Locator много недостатков. В основном, скрывать зависимости не очень хорошая вещь. Потребителю все еще нужно получить свои зависимости, но вместо определения понятного интерфейса они передаются «тайно» и зависят от глобального состояния. В этом примере потребитель не имеет представления о фабрике, он только спрашивает, что ему нужно, и ему не нужно заботиться о том, как эта потребность создается.
Despertar
1
@ MatthewWhited У большинства дизайнерских решений есть компромисс. С DI вы получаете гибкость, прозрачность и более тестируемую систему, но за счет разоблачения ваших смелостей. Многие люди считают это приемлемым компромиссом. Это не значит, что DI всегда лучшее решение, и этот вопрос не об этом. Этот пример предназначен для того, чтобы показать разницу между DI и фабричным шаблоном, показывая некоторые хорошие и плохие варианты использования каждого.
Despertar
3
Это не шаблон DI, это просто реализация IoC. DI использует ServiceLocator для определения правильной зависимости и внедрения ее в конструктор во время создания объекта, ваш код только отделяет создание объектов от области видимости вашего класса.
Диего Мендес
3
@DiegoMendes То, что вы описываете, является структурой, которая автоматизирует DI. ServiceLocator, как вы его называете, делает DI для вас. То, что я показываю, это сам шаблон, который не требует каких-либо модных рамок. См. Stackoverflow.com/a/140655/1160036 или см. En.wikipedia.org/wiki/… : «[список фреймворков] поддерживает внедрение зависимостей, но не требуется делать внедрение зависимостей». Также «Внедрение - это передача зависимости зависимому объекту». Вы слишком усложняете красивую простую концепцию.
Despertar
50

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

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

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

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

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

Tom Maher
источник
3
Это лучший ответ ... другие ответы либо не упоминают IoC, либо не признают, что DI является формой IoC.
Хуман Бахрейни
Спасибо, когда я впервые изучал МОК, я чуть не закричал, что это была просто еще одна форма фабричного образца, оказалось, что они действительно похожи друг на друга
Харви Лин
40

Есть проблемы, которые легко решить с помощью внедрения зависимостей, которые не так легко решить с помощью набора фабрик.

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

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

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

yfeldblum
источник
26

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

BinMaster
источник
22

Управление жизненным циклом является одной из обязанностей контейнеров зависимостей в дополнение к реализации и внедрению. Тот факт, что контейнер иногда сохраняет ссылку на компоненты после создания экземпляра, является причиной того, что он называется «контейнером», а не фабрикой. Контейнеры для инъекций зависимостей обычно содержат только ссылки на объекты, для которых они необходимы для управления жизненными циклами или которые повторно используются для будущих инъекций, такие как синглтоны или мухи. Когда настроено создание новых экземпляров некоторых компонентов для каждого вызова контейнера, контейнер обычно просто забывает о созданном объекте.

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

волчонок
источник
15

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

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

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


источник
14

теория

Есть два важных момента для рассмотрения:

  1. Кто создает объекты

    • [Factory]: вы должны написать, КАК объект должен быть создан. У вас есть отдельный класс Factory, который содержит логику создания.
    • [Внедрение зависимостей]: В практических случаях это делается внешними фреймворками (например, в Java это будет spring / ejb / guice). Инъекция происходит «волшебно» без явного создания новых объектов
  2. Какими объектами он управляет:

    • [Factory]: обычно отвечает за создание объектов с состоянием
    • [Инъекции зависимостей] Более вероятно создание объектов без состояния

Практический пример использования фабричной и зависимой инъекций в одном проекте

  1. Что мы хотим построить

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

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

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

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

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

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

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

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

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

завод

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

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

Вот как это будет выглядеть внутри IDE. Классы вне domainпакета будут использовать OrderFactoryвместо конструктора внутриOrder

  1. Внедрение зависимостей Внедрение зависимостей чаще используется с слоями без состояний, такими как хранилище и сервис.

OrderRepository и OrderService управляются структурой внедрения зависимостей. Репозиторий отвечает за управление операциями CRUD над базой данных. Сервис внедряет репозиторий и использует его для сохранения / поиска правильных классов домена.

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

Марчин Шимчак
источник
Можете ли вы уточнить это? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsЯ не понимаю почему
Максим Дмитриев
2
Объекты с состоянием, скорее всего, находятся в доменном слое приложения, где вы отображаете свои данные в базу данных, в которой вы обычно не используете внедрение зависимостей. Фабрика часто используется для создания AggregateRoot из дерева сложных объектов
Marcin
12

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

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

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

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

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

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

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

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

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

и, наконец, не имеет значения, насколько DI-фреймворк обещает вам, что вы будете строить вещи, отделенные от него, без каких-либо зависимостей от их классов, если вы используете фреймворк, вы создаете все вокруг, если вам нужно изменить подход или рамки это не будет легкой задачей ... КОГДА-ЛИБО! ... но, поскольку вы строите все вокруг этой конкретной структуры, вместо того чтобы беспокоиться о том, какое решение лучше всего подходит для вашего бизнеса, вы столкнетесь с серьезной проблемой при этом.

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

Итак, если у меня есть класс, который по-разному работает в двух областях в одном и том же приложении (скажем, в двух компаниях холдинга), я должен сконфигурировать среду для создания двух разных bean-компонентов и адаптировать свой код для каждого из них. Разве это не то же самое, что если бы я просто написал что-то вроде этого:

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"); 

И таким образом, вы устанавливаете код фабрики, чтобы получить правильную реализацию во время выполнения в зависимости от зарегистрированного пользователя предприятия ?? Теперь это будет полезно. Вы можете просто добавить новый jar с новыми классами и установить правила, возможно, даже во время выполнения (или добавить новый файл конфигурации, если вы оставите эту опцию открытой), без изменений в существующих классах. Это будет динамическая фабрика!

Разве это не было бы более полезным, чем написать две конфигурации для каждого предприятия и, может быть, даже иметь два разных приложения для каждого?

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

Во всяком случае, раздел комментариев, если вы открыты, чтобы убить меня.

Фрэнк Орельяна
источник
3
Слишком многие разработчики считают, что фреймворки Dependency Injection созданы для того, чтобы принести что-то новое. Как вы хорошо объясните, традиционные фабрики (чаще всего абстрактные фабрики) могут играть ту же роль, что и инверсия зависимостей. Инверсия против инъекции? Для меня единственным «преимуществом» инфраструктуры внедрения зависимостей является то, что нам не нужно изменять / перекомпилировать код (так как чаще всего его можно настроить с помощью XML, такого как Spring), когда добавляется / изменяется зависимость. Зачем избегать перекомпиляции? Во избежание некоторых потенциальных человеческих ошибок при изменении зависимости / фабрики. Но с нашими замечательными IDE рефакторинг играет хорошо :)
Mik378
6

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

Тхакур
источник
4

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

На фабриках кто-то должен вызывать их, чтобы доставить сгенерированные объекты туда, где они нужны.

Разница заключается главным образом в этой строке, где вызывается фабрика и извлекается созданный объект.

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

Kosi2801
источник
3

У меня был тот же вопрос, как только я прочитал о DI и оказался на этом посту. Итак, наконец, это то, что я понял, но, пожалуйста, поправьте меня, если я не прав.

«Давным-давно существовали маленькие королевства со своими собственными руководящими органами, контролирующими и принимающими решения на основе своих собственных письменных правил. Позже сформировалось большое правительство, исключающее все эти маленькие руководящие органы, которое имеет один свод правил (конституцию) и реализуется через суды».

Руководящие органы маленьких королевств - "Фабрики"

Большое правительство - «Инжектор зависимостей».

blueskin
источник
1
Итак, КОГДА кто-то считает, что предыдущее маленькое правительство стало большим? По какой мере?
Заключенный НОЛЬ
3

Вы можете взглянуть на эту ссылку для сравнения двух (и других) подходов в реальном примере.

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

Это также справедливо для ручного DI (т. Е. Когда нет внешней структуры, которая предоставляет зависимости вашим объектам, но вы передаете их в каждом конструкторе).

Daniele Pallastrelli
источник
3

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

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

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

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

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

Нелей
источник
2

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

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

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

Harshit
источник
2

Binoj,

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

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

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

Джейсон Слокомб
источник
2

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

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

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

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

Ананд Вемула
источник
1

Мои мысли:

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

bloparod
источник
1
Да, точно. Почти все упоминания инъекций зависимостей (DI) в этих вопросах и ответах неправильно используют термин в отличие от этого определения. Контейнер внедрения зависимостей (DIC) является наиболее распространенной средой, действующей как универсальная и настраиваемая фабрика для создания объектов.
CXJ
1

Injection Framework - это реализация фабричного шаблона.

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

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

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

Мик
источник
1

Фабричный дизайн шаблон

Шаблон дизайна фабрики характеризуется

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

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

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

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

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

Вы можете по-разному вводить зависимость. Для простоты давайте перейдем с интерфейсом инъекции

В DI контейнер создает необходимые экземпляры и «внедряет» их в объект.

Таким образом устраняется статическая реализация.

Пример:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}
Siva Kameswara Rao Munipalle
источник
1

Из номинала они выглядят одинаково

Проще говоря, Factory Pattern, Creational Pattern помогает создать нам объект - «Определить интерфейс для создания объекта». Если у нас есть ключевое значение типа пула объектов (например, словарь), передав ключ к фабрике (я имею в виду простой шаблон фабрики), вы можете разрешить тип. Работа выполнена! С другой стороны, структура внедрения зависимостей (например, Structure Map, Ninject, Unity и т. Д.), Похоже, делает то же самое.

Но ... "Не изобретай велосипед"

С архитектурной точки зрения это связующий слой и «Не изобретай велосипед».

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

В дополнение к «GetType / Create» из Фабрики, чаще всего нам нужны дополнительные функции (возможность использовать XML для определения зависимостей, макетирование и модульное тестирование и т. Д.). Поскольку вы ссылались на Карту структуры, посмотрите на список возможностей Карты структуры . Это явно больше, чем просто разрешение простого сопоставления объектов. Не изобретай велосипед!

Если у вас есть только молоток, все выглядит как гвоздь

В зависимости от ваших требований и типа создаваемого вами приложения, вам необходимо сделать выбор. Если в нем всего несколько проектов (может быть один или два ...) и в нем мало зависимостей, вы можете выбрать более простой подход. Это похоже на использование доступа к данным ADO .Net по сравнению с использованием Entity Framework для простых вызовов базы данных 1 или 2, где внедрение EF в этом сценарии является излишним.

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

Dhanuka777
источник
1

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

Герман ван дер Блом
источник
1

Говоря простым языком, метод зависимости зависимостей от фабрики подразумевает механизм принудительной и последовательной обработки.

Механизм извлечения : класс косвенно зависит от Factory Method, который, в свою очередь, зависит от конкретных классов.

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

С фабричным методом ответственность по-прежнему лежит на классе (хотя и косвенно) за создание нового объекта, где, как и при внедрении зависимостей, эта ответственность передается на аутсорсинг (но за счет утечки абстракции)

Рахул Агарвал
источник
0

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

Мы использовали Spring Framework в Java для DI. Singleton class ( 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);
    }
}
Мартин Колл
источник
0

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

Suhas Tangadle
источник
-1

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

Я использую Фабрику для создания различных объектов Layer (Бизнес, Доступ к данным).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

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

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

Итак, мой код Factory Inpendency Injection выглядит так:

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

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

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

Мишель Баккер
источник
-4

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

Адриан
источник