Injeção de Dependência em Go: para iniciantes — exemplos e princípios

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Injeção de Dependência em Go: para iniciantes



Injeção de Dependência (DI), ou injeção de dependências, é um dos principais padrões de design que ajuda a escrever código limpo, testável e sustentável. No mundo Go, onde simplicidade e clareza são altamente valorizadas, a DI permite evitar a criação de "objetos divinos" e acoplamentos rígidos entre componentes. Neste artigo, vamos explorar o que é Injeção de Dependência em Go, por que ela é necessária e como aplicá-la na prática, usando exemplos simples e fáceis de entender.



O que é Injeção de Dependência?



Imagine que você está escrevendo um programa que envia e-mails de boas-vindas aos usuários. Seu código provavelmente se pareceria com isto:



package main

import "fmt"

type EmailService struct{}

func (e *EmailService) SendWelcomeEmail(userEmail string) { fmt.Printf("Enviando e-mail para %s", userEmail)}

type UserController struct { emailService *EmailService}

func NewUserController() *UserController { return &UserController{ emailService: &EmailService{}, // Acoplamento rígido }}

func (uc *UserController) RegisterUser(email string) { // ... lógica de registro uc.emailService.SendWelcomeEmail(email)}

func main() { controller := NewUserController() controller.RegisterUser("user@example.com")}


O problema deste código é que UserController cria ele mesmo a instância de EmailService. Isso é chamado de acoplamento rígido. Se você quiser substituir EmailService por, digamos, SmsService ou usar um objeto mock para testes, terá que alterar o código dentro de UserController.



Injeção de Dependência resolve esse problema. Em vez de criar dependências dentro da estrutura, nós as "injetamos" de fora. A ideia principal é: "Não pergunte o que você precisa. Diga o que você precisa e receba isso pronto".



Injeção manual de dependências através do construtor



A maneira mais simples e comum de DI em Go é passar dependências através de uma função construtora. Vamos reescrever nosso exemplo:



package main

import "fmt"

// Definimos uma interface para flexibilidadetype Notifier interface { Send(to string, message string) error}

type EmailService struct{}

func (e *EmailService) Send(to string, message string) error { fmt.Printf("Email para %s: %s", to, message) return nil}

type SmsService struct{}

func (s *SmsService) Send(to string, message string) error { fmt.Printf("SMS para %s: %s", to, message) return nil}

type UserController struct { notifier Notifier // Dependência através de interface}

// NewUserController — construtor que aceita a dependênciafunc NewUserController(n Notifier) *UserController { return &UserController{ notifier: n, }}

func (uc *UserController) RegisterUser(email string) { // ... lógica de negócio uc.notifier.Send(email, "Bem-vindo!")}

func main() { // Injetamos a dependência manualmente emailNotifier := &EmailService{} controller := NewUserController(emailNotifier) controller.RegisterUser("user@example.com")

// Facilmente trocamos a implementação smsNotifier := &SmsService{} controller2 := NewUserController(smsNotifier) controller2.RegisterUser("+123456789")}


O que mudou?

  • Definimos a interface Notifier. Agora UserController não sabe qual serviço está sendo usado — Email ou SMS.
  • O construtor NewUserController aceita Notifier como argumento. Isso é injeção de dependência.
  • Em main, nós mesmos decidimos qual implementação passar.


Essa abordagem torna o código flexível, testável e alinhado ao princípio Inversão de Controle.

Blogs

Book Recommendations