[dependency-injection] Инъекция зависимостей против заводского шаблона


Answers

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

Question

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

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

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

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




Инъекционная структура - это реализация Factory Pattern.

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

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

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




Binoj,

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

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

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




Using dependency injection is much better in my opinion if you are: 1. deploying your code in small partition, because it handles well in decoupling of one big code. 2. testability is one of the case DI is ok to use because you can mock easily the non decoupled objects. with the use of interfaces you can easily mock and test each objects. 3. you can simultaneously revised each part of the program without needing to code the other part of it since its loosely decoupled.




теория

Необходимо рассмотреть два важных момента:

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

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

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

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

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

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

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

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

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

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

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

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

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

завод

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

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

  1. Инъекционная инъекция зависимостей Инъекция более широко используется с не имеющими аналогов слоями, такими как репозиторий и служба.

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




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

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

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




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

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




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




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

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

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

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




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

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

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

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

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

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

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

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

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




In simple terms Dependency Injection vs Factory method implies push vs pull mechanism respectively.

With pull mechanism : class indirectly have dependency on Factory Method which in turn have dependency on concrete classes.

With Push mechanism : Root component can be configured with all dependent components in a single location and thus promoting high maintenance and loose coupling.

With Factory method responsibility still lies with class (though indirectly) to create new object where as with dependency injection that responsibility is outsourced (at the cost of leaking abstraction though)




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

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

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




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






Related