Injeção de Dependência em JavaScript
Tags: javascript, tutorial, beginners, oop
Published: 2022-03-08 16:20:56

Neste artigo, será abordado um pouco sobre injeção de dependência, uma técnica muito útil para deixar o sistema mais flexível, diminuindo o acoplamento de código, facilitando assim a manutenção e realização de testes unitários.

## Contextualizando

Em um exemplo da vida real, vamos transcrever a situação para o código:

No restaurante da esquina, existe um garçom que serve um pedaço de pizza para os clientes, mas para conseguir servi-los da melhor forma, o garçom precisa de uma lâmina que consiga cortar um pedaço de pizza.



Nesse caso, podemos ter duas classes:

A classe **Knife** que representa uma faca, tem um método que retorna um pedaço de pizza.

```javascript
class Knife {
	cutPizza() {
		return '🍕 cut by a Knife'
	}
}
```
A classe **Waiter** que representa um garçom, possui um método que serve a pizza, atualmente instanciando uma faca dentro deste método e usando-a para cortar um pedaço e servir.

```javascript
class Waiter {
	servePizza() {
		const knife = new Knife()
		const pizzaSlice = knife.cutPizza()
		return pizzaSlice
	}
}
```

Instanciando as classes e executando o programa temos o seguinte resultado:
```javascript
const waiter1 = new Waiter()
const pizzaSlice = waiter1.servePizza()

console.log(pizzaSlice) // 🍕 cut by a Knife
```
Com o garçom usando uma faca, nosso sistema está funcionando perfeitamente! Mas... E se o chefe do restaurante decidir que agora as pizzas devem ser servidas com um cortador de pizza mais apropriado?

De primeira, pensamos em substituir a **implementação** da classe **Waiter** no método **servePizza()**, substituindo a instância de **Knife** por uma nova classe que saiba cortar pizza.

Funciona, porém sempre irá ter o trabalho de alterar o código interno da classe **Waiter**.

Isso indica que a classe **Waiter** estava acoplada a **Knife** e agora a esta nova classe que foi criada para substituí-la.

E se, depois de contratar dois novos garçons que também estão usando um cortador de pizza, o chefe compra uma machadinha personalizada com o logo da empresa, além disso pede para cada um dos 3 garçons usarem cortadores diferentes?

## Resolvendo o problema

Agora já fica inviável alterar sempre o código interno da classe **Waiter**, enfim iremos utilizar a injeção de dependência para que os garçons consigam servir pizza com qualquer tipo de ferramenta que possa cortá-la.


Para isso, vamos fazer pequenos ajustes na implementação da classe **Waiter**:
```javascript
class Waiter {
	constructor(blade) {
		this.blade = blade
	}
	
	servePizza() {
		const pizzaSlice = this.blade.cutPizza()
		return pizzaSlice
	}
}
```
Adicionamos um construtor que espera receber qualquer objeto de lâmina que possua o método **cutPizza()**, já no método **servePizza()** não instanciamos mais de forma direta uma classe e sim usamos a instância recebida no construtor!

Agora, independentemente de qual for a ferramenta utilizada pelo garçom, desde que ela consiga cortar pizza, será possível servi-la:
```javascript
const knife = new Knife()
const waiter1 = new Waiter(knife)
const pizzaSlice = waiter1.servePizza()

console.log(pizzaSlice) // 🍕 cut by a Knife
```

Exemplificando os três garçons e suas ferramentas diferentes:
```javascript
class PizzaCutter {
	cutPizza() {
		return  '🍕 cut by a Pizza Cutter'
	}
}

class PizzaAxe {
	cutPizza() {
		return  '🍕 cut by a Pizza Axe'
	}
}
```
Definidas as classes das novas ferramentas de cortar pizza, podemos executar nosso código:
```javascript
const knife = new Knife()
const pizzaCutter = new PizzaCutter()
const pizzaAxe = new PizzaAxe()

const waiter1 = new Waiter(knife)
const waiter2 = new Waiter(pizzaCutter)
const waiter3 = new Waiter(pizzaAxe)

const pizzaSlice1 = waiter1.servePizza()
const pizzaSlice2 = waiter2.servePizza()
const pizzaSlice3 = waiter3.servePizza()

console.log(pizzaSlice1) // 🍕 cut by a Knife
console.log(pizzaSlice2) // 🍕 cut by a Pizza Cutter
console.log(pizzaSlice3) // 🍕 cut by a Pizza Axe
```

Agora você já está pronto para criar projetos mais desacoplados e deixar sua aplicação mais flexível!