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.
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.
class Waiter {
servePizza() {
const knife = new Knife()
const pizzaSlice = knife.cutPizza()
return pizzaSlice
}
}
Instanciando as classes e executando o programa temos o seguinte resultado:
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:
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:
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:
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:
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!
Top comments (2)
Show demais. Bem escrito e fácil de entender!
boa!!!!!