285 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			285 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | ||
| title: Dependency Injection
 | ||
| localeTitle: Внедрение зависимости
 | ||
| ---
 | ||
| # Внедрение зависимости
 | ||
| 
 | ||
| #### мотивация
 | ||
| 
 | ||
| Инъекция зависимостей часто более просто называется ДИ. Парадигма существует по всему Угловому. Он сохраняет код гибким, проверяемым и изменяемым. Классы могут наследовать внешнюю логику, не зная, как ее создать. Любые потребители этих классов также не должны знать ничего.
 | ||
| 
 | ||
| DI спасает классы и потребителей от необходимости знать больше, чем необходимо. Тем не менее, код такой же модульный, как и раньше, благодаря механизмам поддержки DI в Angular.
 | ||
| 
 | ||
| Услуги являются ключевым благодетелем ДИ. Они полагаются на парадигму для _инъекций_ различным потребителям. Эти потребители могут воспользоваться этим сервисом и / или перенаправить его в другое место.
 | ||
| 
 | ||
| Служба не одинока. Директивы, трубы, компоненты и т. Д.: Каждая схема в Угловой выгоде от DI так или иначе.
 | ||
| 
 | ||
| #### Форсунки
 | ||
| 
 | ||
| Инъекторы представляют собой структуры данных, в которых хранятся инструкции, детализирующие, где и как формируются службы. Они действуют как посредники в системе Angular DI.
 | ||
| 
 | ||
| Классы модулей, директив и компонентов содержат метаданные, специфичные для инжекторов. Новый экземпляр инжектора сопровождает каждый из этих классов. Таким образом, дерево приложений отражает свою иерархию инжекторов.
 | ||
| 
 | ||
| `providers: []` метаданные принимают службы, которые затем регистрируются в инжекторе класса. Это поле поставщика добавляет инструкции, необходимые для работы инжектора. Класс (при условии, что он имеет зависимости) создает экземпляр службы, беря на себя класс в качестве своего типа данных. Инжектор выравнивает этот тип. A создает экземпляр этой службы для имени класса.
 | ||
| 
 | ||
| Разумеется, класс может только указать, для чего инжектор имеет инструкции. Если собственный инжектор класса не имеет зарегистрированной службы, он запрашивает родителя. Так далее и так далее, пока не дойдете до инжектора с помощью сервиса или корня приложения.
 | ||
| 
 | ||
| Услуги могут регистрироваться у любого инжектора в приложении. Услуги входят в `providers: []` поле метаданных модулей модулей, директив или компонентов. Дети класса могут создавать экземпляр службы, зарегистрированной в инжекторе класса. В конце концов, инъекции инъецированных детей на родительские инжекторы.
 | ||
| 
 | ||
| #### Внедрение зависимости
 | ||
| 
 | ||
| Взгляните на скелеты для каждого класса: сервис, модуль, директива и компонент.
 | ||
| 
 | ||
| ```typescript
 | ||
| // service 
 | ||
|  
 | ||
|  import { Injectable } from '@angular/core'; 
 | ||
|  
 | ||
|  @Injectable({ 
 | ||
|   providedIn: /* injector goes here */ 
 | ||
|  }) 
 | ||
|  export class TemplateService { 
 | ||
|   constructor() { } 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| ```typescript
 | ||
| // module 
 | ||
|  
 | ||
|  import { NgModule } from '@angular/core'; 
 | ||
|  import { CommonModule } from '@angular/common'; 
 | ||
|  
 | ||
|  @NgModule({ 
 | ||
|   imports: [ 
 | ||
|     CommonModule 
 | ||
|   ], 
 | ||
|   declarations: [], 
 | ||
|   providers: [ /* services go here */ ] 
 | ||
|  }) 
 | ||
|  export class TemplateModule { } 
 | ||
| ```
 | ||
| 
 | ||
| ```typescript
 | ||
| // directive 
 | ||
|  
 | ||
|  import { Directive } from '@angular/core'; 
 | ||
|  
 | ||
|  @Directive({ 
 | ||
|   selector: '[appTemplate]', 
 | ||
|   providers: [ /* services go here */ ] 
 | ||
|  }) 
 | ||
|  export class TemplateDirective { 
 | ||
|   constructor() { } 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| ```typescript
 | ||
| //component 
 | ||
|  
 | ||
|  import { Component } from '@angular/core'; 
 | ||
|  
 | ||
|  @Component({ 
 | ||
|   selector: 'app-template', 
 | ||
|   templateUrl: './template.component.html', 
 | ||
|   styleUrls: ['./template.component.css'], 
 | ||
|   providers: [ /* services go here */ ] 
 | ||
|  }) 
 | ||
|  export class TemplateComponent { 
 | ||
|   // class logic ... 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| Каждый скелет может регистрировать услуги инжектора. Фактически, TemplateService _\-_ это сервис. Начиная с Angular 6, службы теперь могут регистрироваться в инжекторах с использованием метаданных `@Injectable` .
 | ||
| 
 | ||
| ##### В любом случае
 | ||
| 
 | ||
| Обратите внимание на `providedIn: string` ( `@Injectable` ) и `providers: []` ( `@Directive` , `@Componet` и `@Module` ) метаданные. Они сообщают инжекторам, где и как создать сервис. В противном случае инжектора не знали, как создавать экземпляр.
 | ||
| 
 | ||
| Что делать, если служба имеет зависимости? Куда будут идти результаты? Поставщики отвечают на этот вопрос, так что инжектора могут корректно создавать экземпляры.
 | ||
| 
 | ||
| Инъекторы образуют основу каркаса DI. Они хранят инструкции для создания служб, которые не нужны потребителям. Они получают экземпляры службы без необходимости знать что-либо об исходной зависимости!
 | ||
| 
 | ||
| Следует также отметить, что другие схемы без инжекторов все еще могут использовать инъекцию зависимостей. Они не могут регистрировать дополнительные услуги, но они все еще могут быть созданы из инжекторов.
 | ||
| 
 | ||
| ##### обслуживание
 | ||
| 
 | ||
| `providedIn: string` метаданные `@Injectable` указывают, какой инжектор зарегистрировать. Используя этот метод, и в зависимости от того, будет ли использоваться услуга, служба может или не может зарегистрироваться в инжекторе. Угловые называет это _дрожание дерева_ .
 | ||
| 
 | ||
| По умолчанию значение установлено на `'root'` . Это переводится в корневой инжектор приложения. В принципе, установка поля в `'root'` делает сервис доступным в любом месте.
 | ||
| 
 | ||
| ##### Быстрая заметка
 | ||
| 
 | ||
| Как упоминалось ранее, детские инъекторы отступают от своих родителей. Эта резервная стратегия гарантирует, что родители не должны перерегистрироваться для каждого инжектора. Обратитесь к этой статье « [Услуги и инжекторы»](https://guide.freecodecamp.org/angular/services-and-injectors) для иллюстрации этой концепции.
 | ||
| 
 | ||
| Зарегистрированные услуги - это _одноточие_ . Смысл, инструкции для создания экземпляра службы существуют только на одном инжекторе. Это предполагает, что он не был явно зарегистрирован в другом месте.
 | ||
| 
 | ||
| ##### Модуль, директива и компонент
 | ||
| 
 | ||
| Модули и компоненты имеют свой собственный экземпляр инжектора. Это очевидно, учитывая `providers: []` поле метаданных. Это поле принимает множество служб и регистрирует их с помощью инжектора модуля или класса компонента. Этот подход происходит в `@NgModule` , `@Directive` или `@Component` .
 | ||
| 
 | ||
| Эта стратегия исключает _дрожание деревьев_ или необязательное удаление неиспользуемых сервисов из инжекторов. Служебные экземпляры живут на своих форсунках в течение всего срока службы модуля или компонента.
 | ||
| 
 | ||
| #### Создание ссылок
 | ||
| 
 | ||
| Ссылки на DOM могут быть экземплярами из любого класса. Имейте в виду, что ссылки по-прежнему являются службами. Они отличаются от традиционных сервисов представлением состояния чего-то другого. Эти сервисы включают функции для взаимодействия со своей ссылкой.
 | ||
| 
 | ||
| Директивы постоянно нуждаются в ссылках DOM. Эти директивы выполняют мутации на своих элементах хоста. См. Следующий пример. Инъектор директивы создает ссылку на главный элемент в конструктор класса.
 | ||
| 
 | ||
| ```typescript
 | ||
| // directives/highlight.directive.ts 
 | ||
|  
 | ||
|  import { Directive, ElementRef, Renderer2, Input } from '@angular/core'; 
 | ||
|  
 | ||
|  @Directive({ 
 | ||
|   selector: '[appHighlight]' 
 | ||
|  }) 
 | ||
|  export class HighlightDirective { 
 | ||
|   constructor( 
 | ||
|     private renderer: Renderer2, 
 | ||
|     private host: ElementRef 
 | ||
|   ) { } 
 | ||
|  
 | ||
|   @Input() set appHighlight (color: string) { 
 | ||
|     this.renderer.setStyle(this.host.nativeElement, 'background-color', color); 
 | ||
|   } 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| ```html
 | ||
| 
 | ||
| // app.component.html 
 | ||
|  
 | ||
|  <p [appHighlight]="'yellow'">Highlighted Text!</p> 
 | ||
| ```
 | ||
| 
 | ||
| `Renderer2` также получает экземпляр. Какой инжектор выполняет эти услуги? Ну, исходный код каждого сервиса исходит от `@angular/core` . Затем эти службы должны регистрироваться в корневом инжекторе приложения.
 | ||
| 
 | ||
| ```typescript
 | ||
| import { BrowserModule } from '@angular/platform-browser'; 
 | ||
|  import { NgModule } from '@angular/core'; 
 | ||
|  import { AppComponent } from './app.component'; 
 | ||
|  import { HighlightDirective } from './directives/highlight.directive'; 
 | ||
|  
 | ||
|  @NgModule({ 
 | ||
|   declarations: [ 
 | ||
|     AppComponent, 
 | ||
|     HighlightDirective 
 | ||
|   ], 
 | ||
|   imports: [ 
 | ||
|     BrowserModule 
 | ||
|   ], 
 | ||
|   providers: [], 
 | ||
|   bootstrap: [ 
 | ||
|     AppComponent 
 | ||
|   ] 
 | ||
|  }) 
 | ||
|  export class AppModule { } 
 | ||
| ```
 | ||
| 
 | ||
| Пустой массив поставщиков !? Не бояться. Угловые регистры автоматически регистрируют многие службы с помощью инжектора корня. Это включает `ElementRef` и `Renderer2` . В этом примере мы управляем элементом хоста через его интерфейс, связанный с созданием `ElementRef` . `Renderer2` позволяет нам обновлять модель DOM через Angular.
 | ||
| 
 | ||
| Вы можете больше узнать о просмотрах из [этой статьи](https://guide.freecodecamp.org/angular/views) . Они являются предпочтительным методом для DOM / просмотра обновлений в Угловых приложениях.
 | ||
| 
 | ||
| Важно признать роль, которую играют инжекторы в приведенном выше примере. Объявляя типы переменных в конструкторе, класс получает ценные сервисы. Тип данных каждого параметра сопоставляется с набором инструкций внутри инжектора. Если инжектор имеет этот тип, он возвращает экземпляр указанного типа.
 | ||
| 
 | ||
| #### Создание служб
 | ||
| 
 | ||
| В статье « [Услуги и инжекторы» подробно](https://guide.freecodecamp.org/angular/services-and-injectors) объясняется этот раздел. Хотя этот раздел повторяет предыдущий раздел или большую часть. Службы часто предоставляют ссылки на что-то еще. Они также могут обеспечить интерфейс, расширяющий возможности класса.
 | ||
| 
 | ||
| Следующий пример будет определять службу ведения журнала, которая будет добавлена в инжектор компонента через своих `providers: []` метаданные.
 | ||
| 
 | ||
| ```typescript
 | ||
| // services/logger.service.ts 
 | ||
|  
 | ||
|  import { Injectable } from '@angular/core'; 
 | ||
|  
 | ||
|  @Injectable() 
 | ||
|  export class LoggerService { 
 | ||
|   callStack: string[] = []; 
 | ||
|  
 | ||
|   addLog(message: string): void { 
 | ||
|     this.callStack = [message].concat(this.callStack); 
 | ||
|     this.printHead(); 
 | ||
|   } 
 | ||
|  
 | ||
|   clear(): void { 
 | ||
|     this.printLog(); 
 | ||
|     this.callStack = []; 
 | ||
|     console.log(“DELETED LOG”); 
 | ||
|   } 
 | ||
|  
 | ||
|   private printHead(): void { 
 | ||
|     console.log(this.callStack[0] || null); 
 | ||
|   } 
 | ||
|  
 | ||
|   private printLog(): void { 
 | ||
|     this.callStack.reverse().forEach((log) => console.log(message)); 
 | ||
|   } 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| ```typescript
 | ||
| // app.component.ts 
 | ||
|  
 | ||
|  import { Component } from '@angular/core'; 
 | ||
|  import { LoggerService } from './services/logger.service'; 
 | ||
|  
 | ||
|  @Component({ 
 | ||
|   selector: 'app-root', 
 | ||
|   templateUrl: './app.component.html', 
 | ||
|   providers: [LoggerService] 
 | ||
|  }) 
 | ||
|  export class AppComponent { 
 | ||
|   constructor(private logger: LoggerService) { } 
 | ||
|  
 | ||
|   logMessage(event: any, message: string): void { 
 | ||
|     event.preventDefault(); 
 | ||
|     this.logger.addLog(`Message: ${message}`); 
 | ||
|   } 
 | ||
|  
 | ||
|   clearLog(): void { 
 | ||
|     this.logger.clear(); 
 | ||
|   } 
 | ||
|  } 
 | ||
| ```
 | ||
| 
 | ||
| ```html
 | ||
| 
 | ||
| // app.component.html 
 | ||
|  
 | ||
|  <h1>Log Example</h1> 
 | ||
|  <form (submit)="logMessage($event, userInput.value)"> 
 | ||
|   <input #userInput placeholder="Type a message..."> 
 | ||
|   <button type="submit">SUBMIT</button> 
 | ||
|  </form> 
 | ||
|  
 | ||
|  <h3>Delete Logged Messages</h3> 
 | ||
|  <button type="button" (click)="clearLog()">CLEAR</button> 
 | ||
| ```
 | ||
| 
 | ||
| Сосредоточьтесь на конструкторе AppComponent и метаданных. Компонент-инжектор получает инструкции из поля метаданных поставщика, содержащего LoggerService. Затем инжектор знает, что создать экземпляр LoggerService из запрошенного в конструкторе.
 | ||
| 
 | ||
| Параметр конструктора `loggerService` имеет тип `LoggerService` который распознает инжектор. Инжектор следует с помощью экземпляра, как уже упоминалось.
 | ||
| 
 | ||
| #### Вывод
 | ||
| 
 | ||
| Инъекция зависимостей (DI) является парадигмой. Способ, которым он работает в Угловом, - это иерархия инжекторов. Класс получает свои ресурсы без необходимости создавать или знать о них. Инъекторы получают инструкцию и создают экземпляр службы в зависимости от того, какой из них был запрошен.
 | ||
| 
 | ||
| DI показывает много в Угловом. Официальная Угловая документация объясняет, почему парадигма настолько распространена. Они также описывают многочисленные варианты использования для DI по Угловому пути, кроме того, что обсуждалось в этой статье. Проверьте это, нажав ниже!
 | ||
| 
 | ||
| ## источники
 | ||
| 
 | ||
| *   [Угловая команда. «Зависимость от инъекции». _Google_ . Доступ к 1 июня 2018 года](https://angular.io/guide/dependency-injection-pattern)
 | ||
|     
 | ||
| *   [Зуев, Алексей. «Что вы всегда хотели знать о дереве инжекции углового зависимостей». _Угловая глубина_ , 21 марта 2018. Доступ к 1 июня 2018 года](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)
 | ||
|     
 | ||
| 
 | ||
| ## Ресурсы
 | ||
| 
 | ||
| *   [Угловая документация](https://angular.io/guide/pipes)
 | ||
|     
 | ||
| *   [Угловой репозиторий GitHub](https://github.com/angular/angular)
 | ||
|     
 | ||
| *   [Введение в инъекцию зависимостей](https://angular.io/guide/architecture-services)
 | ||
|     
 | ||
| *   [Расширенная инъекция зависимостей](https://angular.io/guide/dependency-injection-pattern) |