Boas práticas e padrões · Arquitetura do código · 5 min de leitura
Injeção de dependência
Cada classe recebe o que precisa em vez de criar sozinha — código desacoplado, configurável e fácil de testar.
Arraste para o lado para ver o diagrama inteiro.
Três formas
- Construtor (preferida): dependências obrigatórias e imutáveis, visíveis na assinatura.
- Propriedade/setter: quando o framework cria o objeto (ex.: Activity).
- Parâmetro de método: dependência usada só naquela chamada.
Manual x contêiner
Em projetos pequenos, um objeto AppContainer montando tudo à mão basta (o Android documenta essa abordagem). Em projetos maiores, Koin (DSL em runtime, leve, KMP) ou Hilt/Dagger (gerado em compilação, erros cedo) evitam o código repetitivo e gerenciam escopos.
Testes
Com DI, o teste monta a classe com fakes: BuscarNoticias(FakeRepo()). Sem DI, a classe cria a rede internamente e o teste depende de internet.
No código
class NoticiasRepository(private val http: HttpClient) {
suspend fun ultimas(): List<Noticia> = http.get("/noticias").body()
}
class BuscarNoticias(private val repo: NoticiasRepository) {
suspend operator fun invoke() = repo.ultimas().sortedByDescending { it.data }
}
class NoticiasViewModel(private val buscar: BuscarNoticias) : ViewModel()
// Koin
val appModule = module {
single { HttpClient(OkHttp) { install(ContentNegotiation) { json() } } }
single { NoticiasRepository(get()) }
factory { BuscarNoticias(get()) }
viewModel { NoticiasViewModel(get()) }
} Cada classe declara o que precisa no construtor; o módulo é o único lugar que sabe montar o grafo.
Em resumo
- Prefira injeção pelo construtor.
- DI manual é ótima para começar.
- Koin: simples e multiplataforma; Hilt: checado em compilação.
- Escopos (single/factory) controlam o tempo de vida.