Skip to main content


Injeção de dependência


A injeção de dependência é quando uma classe recebe de fora os objetos que ela precisa usar, em vez de criar esses objetos internamente.


A palavra "dependência" significa algo que uma classe precisa para funcionar, exemplo:

UsuarioService precisa de um Logger.
UsuarioService depende de Logger.

Existem duas formas de fazer isso:

  • Sem injeção A classe cria suas dependências internamente.

  • Com injeção A classe recebe suas dependências prontas.



Exemplo sem injeção de dependência


class Logger {
void info(String mensagem) {
print('[INFO] $mensagem');
}
}

class UsuarioService {
final Logger logger = Logger();

void criarUsuario(String nome) {
logger.info('Criando usuário $nome');
}
}

void main() {
final service = UsuarioService();

service.criarUsuario('Fulano');
}

Aqui, a própria classe UsuarioService cria o Logger:

final Logger logger = Logger();

Isso funciona, mas cria um acoplamento maior, ou seja, o UsuarioService fica preso diretamente à classe Logger. Essa abordagem cria um problema. Imagine que depois você queira trocar o logger.


Com o Logger criado dentro do UsuarioService, fica mais difícil trocar esse comportamento. Um exemplo melhor seria:

class Logger {
void info(String mensagem) {
print('[INFO] $mensagem');
}
}

class UsuarioService {
final Logger logger;

UsuarioService(this.logger);

void criarUsuario(String nome) {
logger.info('Criando usuário $nome');
}
}

void main() {
final logger = Logger();

final service = UsuarioService(logger);

service.criarUsuario('Fulano');
}

Agora o UsuarioService não cria mais o Logger, ele apenas declara que precisa de um (final Logger logger;). Depois ele recebe esse objeto pelo construtor:

UsuarioService(this.logger);

No main, o objeto é criado fora:

final logger = Logger();
final service = UsuarioService(logger);

Isso é injeção de dependência.



Comparação com Python


Como eu tenho maior contato com Python, vou fazer um exemplo para tentar facilitar o entendimento. A ideia seria parecida:

class Logger:
def info(self, mensagem):
print(f'[INFO] {mensagem}')


class UsuarioService:
def __init__(self, logger):
self.logger = logger

def criar_usuario(self, nome):
self.logger.info(f'Criando usuário {nome}')


logger = Logger()
service = UsuarioService(logger)

service.criar_usuario('Fulano')

A lógica é a mesma, a diferença é que em Dart você normalmente declara o tipo, como: final Logger logger;. Enquanto que em Python o tipo não é obrigatório.



Organização de projetos


A organização de projeto é a forma como você separa os arquivos do sistema. Em projetos pequenos, dá para colocar tudo no main.dart, mas conforme o código cresce, isso fica ruim para manter.


A ideia é separar responsabilidades:

bin/
app.dart

lib/
models/
usuario.dart
services/
usuario_service.dart
repositories/
usuario_repository.dart
utils/
logger.dart

Em Dart, normalmente:

  • bin/ Fica para arquivos executáveis, como o ponto de entrada da aplicação.

  • lib/ Fica para o código reutilizável do projeto.


Mas isso não é uma regra, apenas uma convenção.


A estrutura é parecida com o exemplo abaixo:

meu_app/
├── bin/
│ └── app.dart
└── lib/
├── models/
│ └── usuario.dart
├── repositories/
│ └── usuario_repository.dart
├── services/
│ └── usuario_service.dart
└── utils/
└── logger.dart