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

редактировать

В разработке программного обеспечения внедрение зависимостей - это метод, в котором объект получает другие объекты, от которых он зависит. Эти другие объекты называются зависимостями. В типичной взаимосвязи «» использование принимающий объект называется клиентом, а переданный (то есть «внедренным») объект называется службой. Код, который предоставляет услугу клиенту, может быть разнообразным и называется инжектором. Вместо того, чтобы указывал, какую службу он будет использовать, инжектор сообщает, какую службу он будет использовать. «Внедрение» относится к передаче (службы) объекту (клиенту), который будет ее использовать.

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

Целью внедрения зависимостей является достижение разделения задач построения и использования объектов. Это может повысить удобочитаемость и повторное использование кода.

Внедрение зависимостей - одна из форм более широкого метода инверсии управления. Клиент, который хочет вызвать некоторые службы, не должен знать, как построить эти службы. Вместо этого клиент делегирует ответственность за предоставление своих услуг внешнему коду (инжектору). Клиент не имеет права вызывать код инжектора; это инжектор, который строит услуги. Затем инжектор вводит (передает) сервисы клиенту, которые могут быть уже созданы или могут быть созданы инжектором. Затем клиент пользуется услугами. Это означает, что клиенту не нужно знать об инжекторе, о том, как создавать службы, или даже о том, какие фактические службы он использует. Клиенту нужно знать только о внутренних интерфейсах сервисов, потому что они определяют, как клиент может использовать сервисы. Это отделяет ответственность за «использование» от ответственности за «строительство».

Содержание
  • 1 Намерение
  • 2 Обзор
    • 2.1 Таксономия
    • 2.2 Структуры внедрения зависимостей
    • 2.3 Преимущества
    • 2.4 Недостатки
  • 3 Структура
    • 3.1 Класс UML и диаграмма последовательности
  • 4 Примеры
    • 4.1 Без внедрения зависимостей
    • 4.2 Типы внедрения зависимостей
      • 4.2.1 Другие типы
      • 4.2.2 Внедрение конструктора
      • 4.2.3 Внедрение через сеттер
      • 4.2.4 Внедрение интерфейса внедрения
      • 4.2.5 Сравнение внедрения в конструктор
      • 4.2.6 Сравнение внедрения внедрения интерфейса
    • 4.3 Примеры сборки
    • 4.4 Сравнение сборок
    • 4.5 Шаблон внедрения заражений
    • 4.6 Пример AngularJS
    • 4.7 C #
  • 5 См. Также
  • 6 Ссылки
  • 7 Внешние ссылки
Намерение

Внед зависимостей решает такие проблемы, как:

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

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

Класс больше не отвечает за создание необходимых ему объектов, и ему не нужно создать экземпляр объекта фабрики, как в шаблоне проектирования Абстрактная фабрика.. См. Также класс UML и диаграмма следовать ниже.

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

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

Вам следует заявить о своей потребности: «Нам нужно что-нибудь позаботиться о том, чтобы у вас было что-нибудь, когда вы сядете поесть».

Джон Манч, 28 октября 2009 г.

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

Внедрение, основной единица зависимостей, не является новым или настраиваемым механизмом. Он работает так же, как "передача параметров ". Ссылаясь на «передачу параметров» как на инъекцию, подразумевается, что это делается для того, чтобы изолировать клиента от деталей.

Инъекция также касается того, что контролирует передачу (но не клиента), и не зависит от того, как выполняется передача, будь то передача ссылок или значения.

Внедрение зависимости включает четыре роли:

  • объект (ы) службы, который будет работать
  • объект клиент, который зависит от сервис ( ы) использовать он использует
  • интерфейсы, которые определяют, как клиентские сервисы
  • и инжектор, который отвечает за создание сервисов и внедрение их в клиента

По аналогии,

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

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

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

У клиента не быть конкретными методами реализации его зависимостей. Он должен знать только имя интерфейса и API. В результате клиенту не нужно будет менять, даже если изменится то, что стоит за интерфейс. Однако, если интерфейс подвергается рефакторингу с класса на тип интерфейса (или наоборот), клиент должен быть перекомпилирован. Это важно, если клиент и сервисы публикуются отдельно. Это неудачное соединение не может разрешить внедрение внедрения.

Инжектор предоставляет услуги клиенту. Часто он также создает клиент. Инжектор может соединить вместе очень сложный граф объектов, рассматривая объект как клиент, а затем как услугу для другого клиента. На самом деле, на самом деле, может быть поставлена ​​система клиентского множественного инжектора. Инжектор может называться другими именами, такими как: сборщик, контейнер, контейнер, завод, строитель, пружина, код конструкции или основной.

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

Таксономия

Инверсия управления (IoC) является более общим, чем внедрение зависимости. Проще говоря, IoC означает другое коду позвонить вам, а не настаивать на вызове. Пример IoC без внедрения вирусов - шаблон метода шаблон. Здесь полиморфизм достигается посредством подкласса, то есть наследования.

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

Фреймворков внедрения зависимостей

Фреймворков приложений, таких как CDI и его реализации Weld, Spring, Guice, Play framework, Salta, Glassfish HK2, Dagger и Платформа управляемой расширяемости (MEF) включает в себя следующие внедрения, но не обязуются выполнять внедрение зависимостей.

Преимущества

  • Внедрение зависимостей позволяет клиенту гибко настраиваться. Фиксируется только поведение клиента. Клиент может воздействовать на все, что поддерживает внутренний интерфейс, который ожидает клиент.
  • Внедрение представлений может внести изменения в конфигурацию системы в конфигурации, что позволяет настроить систему без перекомпиляции. Можно написать отдельные конфигурации для разных действий, требующих разных реализаций компонентов. Это включает, но не ограничивается, тестирование.
  • Варианты внедрения не требует каких-либо изменений в поведении кода, его можно применить к унаследованному коду в качестве рефакторинга. В результате клиенты становятся более независимыми и легче тестируются изолированно, используя заглушки или имитирующие объекты, которые имитируют другие объекты, не тестируемые. Это простота тестирования часто является первым преимуществом, которое происходит при использовании зависимостей.
  • Внедрение зависимостей позволяет клиенту удалить все знания о специфической реализации, которые ему необходимо использовать. Это помогает изолировать клиента от воздействия изменений конструкции и дефектов. Это повторному использованию, тестированию и сопровождению.
  • Уменьшение шаблонного кода в объекте приложения, поскольку вся работа по инициализации или настройке осуществляется через поставщика услуг поставщика.
  • Внедрение зависимостей позволяет равную или независимую компьютер. Два разработчика могут независимо разрабатывать классы, которые используют друг друга, через которые им нужно знать интерфейс, через который классы будут взаимодействовать. Плагины часто используются сторонними поставщиками, которые даже не разговаривают с разработчиками, которые создают продукт, использующий плагины.
  • Внедрение зависимостей снижает связь между классом и его зависимостью.

Недостатки

  • Внедрение требуются рабочие органы, которым нужны детали конфигурации. Это может быть обременительным, когда доступны очевидные значения по умолчанию.
  • Внедрение зависимостей может затруднить отслеживание (чтение), поскольку оно может отделяет поведение от построения. Это означает, что разработчики должны обращаться к большему количеству файлов, чтобы следить за работой системы.
  • Каркасы внедрения зависимостей реализованы с помощью отражения или динамического программирования. Это может помешать использование IDE, такой как «поиск ссылок», «отображение иерархии содержит» и безопасный рефакторинг.
  • Внедрение зависимостей обычно требует использования при разработке, когда он необходим, но должен использовать его внедрение, а затем, что он был введен.
  • Внедрение зависимостей заставляет сложность перемещаться из классов в связи между классами.
  • Внедрение вредных организмов вредных организмов.
Структура

Класс UML и диаграмма следовать

Пример класса UML и диаграмма следовать для разработки проектирования внедрения зависимостей.

В приведенной выше диаграмме классов UML класс Client, которым требуются объекты ServiceAи ServiceB, выполняет не создавать экземпляры классов ServiceA1и ServiceB1напрямую. Вместо этого класс Инжекторсоздает объекты и внедряет их в Клиент, что делает Клиентнезависимым от того, как проекты объектов (какие классы классифицируют).. На диаграмме использовать UML продемонстрировано взаимодействие во время выполнения: объект ИнжекторServiceA1и ServiceB1объекты. После этого Injectorсоздает объект Clientи внедряет объекты ServiceA1и ServiceB1.

Примеры

Без внедрения зависимостей

В следующем примере Java класс Client содержит переменную-член Service , которая является инициализируется конструктором клиент. Клиент контролирует, какая реализация службы используется, и контролирует ее построение. В этой ситуации, что клиент имеет жестко заданную зависимость от ExampleService.

// Пример без внедрения публичного класса Client {// Внутренняя ссылка на службу, используемую этим клиентом private ExampleService service; // Конструктор Client () {// Укажите конкретную реализацию в конструкторе вместо использования внедрения внедрений service = new ExampleService (); } // Метод в этом клиенте, который использует службы public String greet () {return "Hello" + service.getName (); }}

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

Типы внедрения зависимостей

Существует по крайней мере три способа, клиентский объект может получить ссылку на внешний модуль:

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

Другие типы

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

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

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

Внедрение конструктора

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

// Клиент-конструктор (сервис-сервис) {// Сохраняем ссылку на переданный сервис внутри этого клиента this.service = service; }

Внедрение установщика

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

// Метод установки public void setService (Service service) {// Сохраняем ссылку на переданную службу внутри этого клиента. this.service = service; }

Внедрение интерфейса

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

// Интерфейс установщика службы. общедоступный интерфейс ServiceSetter {public void setService (Сервисная служба); } // Класс клиента Открытый класс Клиент реализует ServiceSetter {// Внутренняя ссылка на службу, используемую этим клиентом. частное сервисное обслуживание; // Устанавливаем службу, которую должен использовать этот клиент. @Override public void setService (Сервисная служба) {this.service = service; }}

Сравнение внедрения конструктора

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

// Клиент-конструктор (служба службы, служба otherService) {if (service == null) {выбросить новое исключение InvalidParameterException («услуга не может быть нулевой»); } if (otherService == null) {throw new InvalidParameterException ("otherService не должен быть нулевым"); } // Сохраняем ссылки на сервисы внутри этого клиента this.service = service; this.otherService = otherService; }

Сравнение внедрения установщика

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

// Устанавливаем службу, которая будет использоваться этим клиентом public void setService (Service service) {if (service == null) {throw new InvalidParameterException ("service не должно быть нулевым"); } this.service = service; } // Устанавливаем другую службу для использования этим клиентом public void setOtherService (Service otherService) {if (otherService == null) {throw new InvalidParameterException ("otherService не должен быть нулевым"); } this.otherService = otherService; }

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

// Устанавливаем службу, которая будет использоваться этим клиентом public void setService (Service service) {this.service = service; } // Устанавливаем другой сервис, который будет использоваться этим клиентом public void setOtherService (Service otherService) {this.otherService = otherService; } // Проверяем ссылки на службы этого клиента private void validateState () {if (service == null) {throw new IllegalStateException ("service не должно быть нулевым"); } if (otherService == null) {выбросить новое исключение IllegalStateException («otherService не должен быть нулевым»); }} // Метод, использующий эту службу, ссылается на public void doSomething () {validateState (); service.doYourThing (); otherService.doYourThing (); }

Сравнение внедрения интерфейса

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

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

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

// Интерфейс установщика службы. общедоступный интерфейс ServiceSetter {public void setService (Сервисная служба); } // Класс клиента Открытый класс Клиент реализует ServiceSetter {// Внутренняя ссылка на службу, используемую этим клиентом. частное сервисное обслуживание; // Устанавливаем службу, которую должен использовать этот клиент. @Override public void setService (Сервисная служба) {this.service = service; }} // Класс инжектора открытый класс ServiceInjector {Set clients; public void inject (клиент ServiceSetter) {clients.add (client); client.setService (новый ServiceFoo ()); } public void switchToBar () {для (Клиент-клиент: клиенты) {client.setService (новый ServiceBar ()); }}} // Сервисные классы открытый класс ServiceFoo реализует Сервис {} открытый класс ServiceBar реализует Сервис {}

Примеры сборки

Ручная сборка в основном является вручную одними из способов реализации зависимостей.

public class Injector {public static void main (String args) {// Сначала строим зависимости Service service = new ExampleService (); // Внедрение службы в стиле конструктора Client client = new Client (услуга); // Использование объектов System.out.println (client.greet ()); }}

В приведенном выше примере граф объекта создается вручную, затем вызывается в какой-то момент, чтобы он начал работать. Важно отметить, что этот инжектор не чистый. Он использует один из конструируемых объектов. Он имеет чисто конструктивные отношения с ExampleService, но смешивает построение и использование Client. Это не должно быть обычным явлением. Однако это неизбежно. Точно так же, как объектно-ориентированному программному обеспечению для работы нужен объектно-ориентированный статический метод, такой как main (), графу внедренных зависимостей требуется как минимум одна (желательно только одна) точка входа, чтобы все это начало.

Ручное построение в основном методе может быть непростым и может вызывать вызов builders, factory или других шаблонов построения.. Это может быть довольно сложно и абстрактно. Граница переходит от ручного внедрения зависимостей к структура инъекция зависимостей, как только код построения является не индивидуальным для приложения.

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

импортировать org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; открытый класс Injector {public static void main (String args) {// - Сборка объектов - // BeanFactory beanfactory = new ClassPathXmlApplicationContext ("Beans.xml"); Клиент client = (Клиент) beanfactory.getBean («клиент»); // - Использование объектов - // System.out.println (client.greet ()); }}

Фреймворки, такие как Spring, позволяют выводить детали сборки в файлы конфигурации. Этот код (вверху) конструирует объекты и связывает их вместе в соответствии с Beans.xml (внизу). ExampleService все еще создается, хотя он регистрируется только ниже. Таким образом можно определить длинный и сложный граф объектов, единственный класс, указанный в коде, будет иметь метод точки входа, соответствующий в данном случае является greet ().

В приведенном выше примере Клиент и Служба не претели каких-либо изменений, которые предоставлены к весне. Им разрешено оставаться простыми POJO. Это показывает, как Spring может соединять сервисы и клиентов, которые совершенно не подозревают о его существовании. Этого нельзя было бы сказать, если бы к классам были добавлены аннотации Spring. Не позволяя аннотациям и вызовам Spring распространяться среди множества, система остается лишь слабо зависимой от Spring. Это может быть важно, если система намеревается пережить весну.

Решение сохранить чистоту POJO не обойдется без затрат. Вместо этого можно просто использовать аннотации для пометки классов и Spring сделать остальную работу. Устранение зависимостей может быть основным, если они следуют соглашению, например, по типу или по имени. Это означает выбор соглашения вместо конфигурации. Также можно утверждать, что при рефакторинге под другую платформу удаление аннотаций, специфичных для данной платформы, было тривиальной частью задачи, и многие аннотации внедрения теперь стандартизированы.

импортировать org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Injector {public static void main (String args) {// Собираем объекты BeanFactory beanfactory = new AnnotationConfigApplicationContext (MyConfiguration.class); Клиент client = beanfactory.getBean (Client.class); // Использование объектов System.out.println (client.greet ()); }}
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @ComponentScan публичный класс MyConfiguration {@Bean публичный клиентский клиент (сервис ExampleService) {return new Client (service); }}
@Component открытый класс ExampleService {public String getName () {return "World!"; }}

Сравнение сборок

Различные реализации инжектора (фабрики, локаторы сервисов и контейнеры внедрения зависимостей) не так уж сильно различаются в том, что вызывает внедрение зависимостей. Вся разница в том, где их можно использовать. Переместите вызовы к фабрике или локатору сервисов из клиента в главный, и вдруг становится довольно контейнером для заражения.

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

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

Шаблоны внедрения внедрений

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

public static void main (String args) выбрасывает IOException {// Строительный код. Greeter greeter = новый Greeter (System.out); // Это может быть много строк, которые соединяют множество объектов // Код поведения. greeter.greet (); // Это один вызов одного метода для одного объекта в графе объектов} class Greeter {public void greet () {this.out.println ("Hello world!"); } общедоступный Greeter (PrintStream out) {this.out = out; } частный PrintStream out; }

Пример AngularJS

В структуре AngularJS есть только три метода, подходящего компонента (объект или функция) может напрямую обращаться к своим зависимостям:

  1. Компонент может создавать зависимость, обычно с С помощью оператора новая.
  2. Компонент может искать, ссылаясь на глобальную переменную.
  3. Компоненту может быть передана зависимость, где это необходимо.

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

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

функция SomeClass (greeter) {this.greeter = greeter; } SomeClass.prototype.doSomething = функция (имя) {this.greeter.greet (имя); }

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

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

Для управления зависимостями от каждого приложения AngularJS имеет инжектор. Инжектор - это сервисный локатор, который отвечает за построение и поиск зависимостей.

Вот пример использования службы инжектора:

// Предоставляем информацию о подключении в модуле var myModule = angular.module ('myModule',); // Обучаем инжектора, как создать службу приветствия. // программа приветствия зависит от службы $ window. // Служба приветствия - это объект, // вызов метод приветствия. myModule.factory ('приветствие', функция ($ window) {return {greet: function (text) {$ window.alert (text);}};});

Создайте новый инжектор, который может выступать в модуле myModule, и запросите нашу услугу приветствия у инжектора. (Обычно это делается автоматически с помощью начальной загрузки AngularJS).

var injector = angular.injector (['myModule', 'ng']); var greeter = injector.get ('приветствующий');

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

, функция MyController ($ scope, greeter) {$ scope. sayHello = функция () {greeter.greet ('Привет, мир'); }; }

Когда AngularJS компилирует HTML, он обрабатывает директиву ng-controller, которая, в свою очередь, просит инжектор создать экземпляр контроллера и его зависимостей.

injector.instantiate (MyController);

Все это делается за кадром. Поскольку ng-controllerподчиняется инжектору для создания экземпляра класса, он может удовлетворить все зависимости MyController, даже если контроллер никогда не узнает о инжекторе. Код приложения просто объявляет необходимые ему зависимости без необходимости иметь дело с инжектором. Эта установка не нарушает Закон Деметра.

C#

Пример внедрения конструктора, внедрения в сеттер и внедрения интерфейса на C #

с использованием Система; namespace DependencyInjection {// Интерфейс для интерфейса библиотеки IGamepadFunctionality {String GetGamepadName (); void SetVibrationPower (float InPower); } // Конкретная реализация функциональности контроллера xbox class XBoxGamepad: IGamepadFunctionality {readonly String GamepadName = "XBox Controller"; float VibrationPower = 1.0f; общедоступная строка GetGamepadName () =>GamepadName; public void SetVibrationPower (float InPower) =>VibrationPower = Math.Clamp (InPower, 0.0f, 1.0f); } // Конкретная реализация класса функциональности контроллера playstation PlaystationJoystick: IGamepadFunctionality {readonly String ControllerName = "Playstation controller"; float VibratingPower = 100.0f; общедоступная строка GetGamepadName () =>ControllerName; public void SetVibrationPower (float InPower) =>VibratingPower = Math.Clamp (InPower * 100.0f, 0.0f, 100.0f); } // Конкретная реализация функциональности парового контроллера class SteamController: IGamepadFunctionality {readonly String JoystickName = "Steam controller"; двойная вибрация = 1.0; общедоступная строка GetGamepadName () =>JoystickName; public void SetVibrationPower (float InPower) =>Vibrating = Convert.ToDouble (Math.Clamp (InPower, 0.0f, 1.0f)); } // Интерфейс для внедрения функциональности геймпада interface IGamepadFunctionalityInjector {void InjectFunctionality (IGamepadFunctionality InGamepadFunctionality); } class CGamepad: IGamepadFunctionalityInjector {IGamepadFunctionality _GamepadFunctionality; public CGamepad () {} // Внедрение конструктора public CGamepad (IGamepadFunctionality InGamepadFunctionality) =>_ GamepadFunctionality = InGamepadFunctionality; // Установление инъекции public void SetGamepadFunctionality (IGamepadFunctionality InGamepadFunctionality) =>_ GamepadFunctionality = InGamepadFunctionality; // Внедрение интерфейса public void InjectFunctionality (IGamepadFunctionality InGamepadFunctionality) =>_ GamepadFunctionality = InGamepadFunctionality; public void Showcase () {String Message = String.Format («Мы используем {0} прямо сейчас, вы хотите изменить мощность вибрации? \ r \ n», _GamepadFunctionality.GetGamepadName ()); Console.WriteLine (Сообщение); }} перечисление EPlatforms: байт {Xbox, Playstation, Steam} class CGameEngine {EPlatforms _Platform; CGamepad _Gamepad; public void SetPlatform (EPlatforms InPlatform) {_Platform = InPlatform; switch (_Platform) {case EPlatforms.Xbox: // внедряет зависимость от класса XBoxGamepad через Constructor Injection _Gamepad = new CGamepad (new XBoxGamepad ()); перемена; case EPlatforms.Playstation: _Gamepad = new CGamepad (); // внедряет зависимость от класса PlaystationJoystick через Setter Injection _Gamepad.SetGamepadFunctionality (новый PlaystationJoystick ()); перемена; case EPlatforms.Steam: _Gamepad = new CGamepad (); // внедряет зависимость от класса SteamController через Внедрение интерфейса _Gamepad.InjectFunctionality (new SteamController ()); перемена; } _Gamepad.Showcase (); }} класс Program {static void Main (string args) {Console.WriteLine ("Hello World!"); CGameEngine Engine = новый CGameEngine (); Engine.SetPlatform (EPlatforms.Steam); Engine.SetPlatform (EPlatforms.Xbox); Engine.SetPlatform (EPlatforms.Playstation); }}}
См. Также
Ссылки
Внешние ссылки
На Викискладе есть средства информации, связанные с Внедрение зависимостей.

Последняя правка сделана 2021-05-17 13:56:59
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте