Boas práticas e padrões · Padrões de criação · 4 min de leitura
Singleton (e por que usar com cuidado)
Garante uma única instância de uma classe — útil para recursos caros, mas vira estado global se usado sem critério.
Arraste para o lado para ver o diagrama inteiro.
Quando faz sentido
Recursos caros e compartilhados: conexão com banco (o Room recomenda uma instância por app), cliente HTTP com pool de conexões, cache em memória. Em Kotlin, object já é um singleton seguro entre threads.
Os problemas
- Estado global escondido: qualquer classe pode alterá-lo; bugs que dependem da ordem dos testes.
- Acoplamento invisível: a dependência não aparece no construtor.
- Difícil de testar: não dá para trocar por um fake.
A alternativa moderna
Mantenha uma instância, mas entregue-a por injeção de dependência com escopo de aplicação (Koin single { }, Hilt @Singleton). Use object apenas para coisas sem estado (funções utilitárias, constantes).
No código: antes e depois
object Sessao { var usuario: Usuario? = null } // qualquer lugar lê e escreve
class Carrinho { fun dono() = Sessao.usuario!!.nome } // dependência invisível class SessaoRepository { private val _usuario = MutableStateFlow<Usuario?>(null); val usuario = _usuario.asStateFlow() }
class Carrinho(private val sessao: SessaoRepository) // dependência explícita
// Koin: uma instância para o app inteiro, entregue a quem pedir
val appModule = module {
single { SessaoRepository() }
factory { Carrinho(get()) }
} Continua existindo uma única sessão, mas agora ela é imutável por fora, aparece no construtor e pode ser substituída em teste.
Em resumo
- Uma instância ≠ acesso global.
- object em Kotlin é ótimo para código sem estado.
- Recursos com estado: escopo único via DI.
- Singletons globais dificultam testes paralelos.