Services e injeção de dependência no Angular: o que são e como funcionam?

Services e injeção de dependência no Angular: o que são e como funcionam?
Nayanne Batista
Nayanne Batista

Compartilhe

Injeção de dependência é um termo que pode parecer assustador para quem está iniciando na área de programação, mas não é um bicho de sete cabeças. Hoje vamos acabar com o medo dessa injeção através deste artigo e aprender com exemplos simples:

  • O que é injeção de dependência;
  • Como utilizar a injeção de dependência no Angular;
  • Quais as vantagens desse padrão de projeto;
  • O que é e como criar um serviço injetável;
  • Como injetar serviços em componentes e em outros serviços.

Se você está começando agora, aprenda como criar sua primeira aplicação Angular e quais os primeiros passos com este framework.

O que é injeção de dependência?

Considere o seguinte exemplo: se a classe A precisa de informações da classe B para poder funcionar, então, A depende de B, ou seja, B é uma dependência para A. Olhando para um outro contexto: sabe quando você acorda super cedo para treinar e depende do seu cafezinho para conseguir fazer os exercícios?

Nayanne, então, você está dizendo que o café é a minha dependência?

Isso mesmo, é essa a ideia!

De forma mais técnica, dependências são serviços, objetos, funções ou até mesmo um valor que uma classe necessita para desempenhar sua função. No nosso exemplo, a classe A pode ela mesma ser responsável por criar uma instância da classe B, ou então, essa dependência pode ser passada para ela, ou melhor dizendo, ser injetada nela. Esse processo recebe o nome de injeção de dependência.

De acordo com a documentação do Angular, injeção de dependência é um padrão de projeto no qual uma classe solicita dependências de fontes externas ao invés de criá-las.

Como utilizar injeção de dependência no Angular?

Para exemplificar como funciona a injeção de dependência no Angular, vamos aprender a criar serviços (services) injetáveis e utilizá-los em um componente da nossa aplicação. Mas antes vamos entender o que são serviços.

O que são services?

Os arquivos em Angular possuem responsabilidades bem definidas. É uma boa prática que o componente contenha apenas a lógica para definir comportamentos e conseguir renderizar os arquivos na tela. Assim, é necessário que haja um arquivo para guardar toda a lógica de negócios e que seja responsável pela comunicação com o servidor. Esse arquivo é o service.

Os serviços no Angular nos auxiliam a separar do componente algumas informações importantes e também o modo como vamos obtê-las, lógica de negócios, além de dados de requisições ao servidor. Eles são úteis porque o código contido neles pode ser utilizado por toda a aplicação e não será repetido em vários locais diferentes, visto que essas funcionalidades podem ser compartilhadas entre os componentes.

Como criar um serviço injetável?

Temos uma aplicação de delivery e vamos criar um serviço chamado FoodService, utilizando o seguinte comando do Angular CLI:

ng generate service food

ou a forma abreviada:

ng g s food

Será gerado um arquivo com a seguinte estrutura:

food.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})

export class FoodService {
  constructor() { }

Analisando este arquivo, percebemos que se trata de uma classe que contém um decorator chamado @Injectable(), importado do pacote @angular/core. Esse decorator indica ao Angular que essa classe é injetável e pode ser utilizada em outras classes.

O decorator @injectable(), por padrão, possui um metadado chamado providedIn. Esse nome vem de provider (provedor), que significa fornecedor. Ele é o responsável por fornecer uma instância dessa classe através da injeção de dependência. Nesse caso, o valor dessa propriedade: providedIn: 'root', indica que o Angular deve fornecer o serviço no injetor raiz, em outras palavras, significa que esse serviço é visível para toda a aplicação e você pode injetá-lo em qualquer lugar do seu projeto.

Então, agora que já sabemos como criar serviços injetáveis, vamos aprender como usá-los em nossos componentes?

Como injetar serviços em componentes?

Para mostrar a injeção de dependência em ação, vamos utilizar o seguinte exemplo.

Imagine que durante um dia mais corrido, você não tenha tempo de preparar uma refeição e decida ir a um restaurante. Você precisa enfrentar o trânsito para ir de bike ou de carro até lá, pegar o cardápio, esperar ser atendido, fazer o pedido e depois pagar por ele. Mas, e se houvesse um jeito mais prático e fácil de fazer isso? E se, ao invés de você ir até o restaurante, o pedido viesse até você? Isso pode ser resolvido por meio de um pedido de refeições via aplicativo, certo?

Note que, ao fazer o pedido pelo aplicativo, você não fica mais responsável por todo o processo e deixa isso a cargo do serviço de delivery, não é mesmo? Bem, esse é outro exemplo de injeção de dependência e é com esse contexto que vamos exemplificar o uso de serviços em componentes.

Imagem exemplificando o modo tradicional de ir até o restaurante para fazer a refeição e o modo simplificado fazendo o pedido pelo aplicativo. Nesse caso o serviço de delivery seria a dependência injetada.

No nosso projeto, temos um componente chamado delivery, que é utilizado para renderizar na tela as opções de pedidos num restaurante. Esse componente precisa do serviço que criamos anteriormente, o FoodService, para a escolha do tipo de refeição.

Em alguns dias da semana, o restaurante faz uma promoção para as pessoas que quiserem pedir, além da refeição, uma sobremesa ou uma bebida. Nesse caso, o FoodService precisa se comunicar com outros dois serviços, o DessertService e o DrinkService.

Imagem mostrando um título: Escolha seu pedido e três botões cor de laranja com os nomes: Refeições; Refeição + sobremesa e Refeição + drink.

Agora, vamos ao código ver como resolver isso!

Sem a injeção de dependência, teríamos que instanciar manualmente todos os serviços de que precisamos no componente, além de ter que passar todos os possíveis parâmetros que esses serviços utilizam. Assim:

delivery.component.ts

export class DeliveryComponent {

   drinkService = new DrinkService();
   dessertService = new DessertService();
   foodService = new FoodService(this.dessertService, this.drinkService);

  //métodos da classe
}

Já imaginou o trabalhão? Além do acoplamento de classes, repetição de código e dificuldade nos testes que isso iria causar na sua aplicação? E olha que esse componente utiliza apenas três serviços. Definitivamente, não queremos criar essas classes manualmente, queremos que o serviço nos forneça isso.

Vamos ao exemplo com injeção de dependência:

delivery.component.ts

export class DeliveryComponent {

  constructor(private foodService: FoodService) { }

  //métodos da classe
}

Sim, é só isso mesmo! No Angular, a injeção de dependência é feita via construtor, onde especificamos um parâmetro com o tipo da dependência (foodService: FoodService) e ao, colocar o modificador de acesso private, fazemos com que esse atributo seja automaticamente declarado como atributo dessa classe.

Assim, o DeliveryComponent está pedindo para o FoodService ser injetado, em vez de criar sua própria instância dessa classe de serviço.

Certo, mas e como o FoodService está consumindo os outros dois serviços? Vamos ao próximo tópico!

Usando serviços em outros serviços

Para usar serviços em outros serviços, a abordagem é semelhante à que realizamos para injetar essas classes em componentes. Abaixo, temos o arquivo FoodService com os outros dois serviços sendo injetados via construtor e alguns métodos de exemplo consumindo dados referentes às classes injetadas, apenas para visualizarmos no navegador que está tudo certo.

food.service.ts

import { DrinkService } from '../drink/drink.service';
import { DessertService } from '../dessert/dessert.service';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class FoodService {

  constructor(
    private dessertService: DessertService,
    private drinkService: DrinkService
  ) { }

  food!: string;

  selectFood(food: string) {
    this.food = food;
    console.log(this.food);
  }

  selectFoodAndDessert(food: string, dessert: string) {
    this.selectFood(food);
    this.dessertService.selectDessert(dessert);
  }

  selectFoodAndDrink(food: string, drink: string) {
    this.selectFood(food);
    this.drinkService.selectDrink(drink);
  }

}

Resumindo, fizemos a injeção dos serviços DrinkService e DessertService no FoodService e injetamos apenas este último no nosso componente. Na imagem abaixo, pelas mensagens no console do navegador, vemos que no componente delivery podemos consumir informações dos três serviços. Tudo isso, por meio da injeção de dependência! Que demais, né?

Imagem mostrando um título: Escolha seu pedido e três botões cor de laranja com os nomes: Refeições; Refeição + sobremesa e Refeição + drink e ao lado, imagem do console do navegador mostrando mensagens referentes aos serviços injetados.

Bônus: 10 motivos para usar injeção de Dependência

Vimos os recursos para que o Angular forneça automaticamente uma instância do serviço de modo a ser utilizada sem nos preocuparmos em instanciá-la manualmente. Além disso, vou te dar mais 10 motivos para começar a usar injeção de dependência:

  • aumentar a flexibilidade e a modularidade em suas aplicações;
  • diminuir código boilerplate (código repetitivo, em várias partes do projeto);
  • deixar seu código mais limpo e eficiente;
  • ajudar no gerenciamento de dependências;
  • melhorar a reutilização do código;
  • permitir a clara separação de responsabilidades entre os arquivos;
  • diminuir o acoplamento entre as classes;
  • facilitar a manutenção de código;
  • possibilitar a alteração do serviço sem afetar os componentes dependentes;
  • favorecer o desenvolvimento de testes unitários usando dependências simuladas.

Conclusão

Neste artigo, nós entendemos o que significa dependência, injeção de dependência e serviços e aprendemos como utilizar esses conceitos de forma prática no Angular. Agora, você sabe criar serviços injetáveis para serem consumidos por componentes e outros serviços, organizando melhor sua aplicação.

Querida Dev e querido Dev, espero que você tenha aprendido algo novo com este artigo e se interessado em estudar mais sobre o tema! Espero te encontrar em breve em mergulhos no Angular! Até mais!

Conheça mais sobre injeção de dependência e services no Angular.

Veja também as nossas formações:

Nayanne Batista
Nayanne Batista

Nayanne (Nay) é uma paraibana arretada que fez transição de carreira para a TI depois de concluir um doutorado na área da saúde e ser professora no ensino superior. Já atuou como Dev Frontend em projetos e hoje é Instrutora na Alura. Acredita completamente no poder transformador da educação e da tecnologia na vida das pessoas. Ama livros e café! :)

Veja outros artigos sobre Front-end