Injeção de Dependência em JavaScript: o que é e para que serve
No mundo do desenvolvimento moderno em JavaScript (Node.js), a clareza e a manutenibilidade do código tornam-se criticamente importantes. Um dos princípios-chave que ajudam a alcançar isso é a Injeção de Dependência (DI) — dependency injection. Este artigo foi criado especialmente para iniciantes, para explicar o conceito de forma simples com exemplos práticos.
Imagine que você está montando um computador. Em vez de soldar a placa de vídeo diretamente na placa-mãe para sempre, você usa slots PCI-E. Isso permite substituir facilmente a placa de vídeo por uma mais potente ou usar outra para testes. A Injeção de Dependência funciona pelo mesmo princípio: você não cria dependências dentro da classe (não as "solda"), mas as passa de fora.
O problema sem Injeção de Dependência
Vamos considerar um exemplo típico em Node.js, onde o código se torna fortemente acoplado (tightly coupled):
class Logger { log(message) { console.log(`[LOG]: ${message}`); }}
class UserService { constructor() { this.logger = new Logger(); // Dependência rígida }
createUser(name) { this.logger.log(`Usuário criado: ${name}`); // Lógica de criação de usuário }}
const service = new UserService();service.createUser('Ana');Aqui, UserService cria ele mesmo uma instância de Logger. Se quisermos substituir console.log por gravação em arquivo ou banco de dados, teremos que alterar o código de UserService. Isso viola o princípio aberto/fechado (Open/Closed Principle) do SOLID.
Fundamentos da Injeção de Dependência em JavaScript
O que é Injeção de Dependência?
Injeção de Dependência (DI) é um padrão de projeto no qual um objeto recebe suas dependências de uma fonte externa, em vez de criá-las por conta própria. No contexto do JavaScript, isso significa passar dependências através do construtor, de um setter ou de um parâmetro de método.
Três principais formas de injeção de dependências
Em JavaScript e Node.js, três abordagens são aplicadas:
- Injeção por Construtor (Constructor Injection): as dependências são passadas através do construtor da classe.
- Injeção por Setter (Setter Injection): as dependências são definidas através de um método separado (setter).
- Injeção por Método (Method Injection): as dependências são passadas diretamente no método que as utiliza.
A mais popular e recomendada é a Injeção por Construtor, pois torna as dependências explícitas e imutáveis após a criação do objeto.
Exemplos práticos de Injeção de Dependência em Node.js
Exemplo 1: Injeção por Construtor
Vamos reescrever nosso exemplo usando Injeção de Dependência:
class Logger { log(message) { console.log(`[LOG]: ${message}`); }}
class FileLogger { log(message) { // Simulação de gravação em arquivo console.log(`[FILE]: ${message}`); }}
class UserService { constructor(logger) { this.logger = logger; // Dependência passada de fora }
createUser(name) { this.logger.log(`Usuário criado: ${name}`); // Lógica de criação de usuário }}
// Uso com diferentes loggersconst consoleLogger = new Logger();const fileLogger = new FileLogger();
const serviceWithConsole = new UserService(consoleLogger);serviceWithConsole.createUser('Ana'); // [LOG]: Usuário criado: Ana
const serviceWithFile = new UserService(fileLogger);serviceWithFile.createUser('João'); // [FILE]: Usuário criado: JoãoAgora, UserService não sabe qual logger está sendo usado. Nós