Singleton | Flutter
- Singleton | Flutter
🧩 1. ✅ O padrão clássico com factory + _internal()
Essa é a forma mais comum e idiomática em Dart.
Você cria uma instância estática e faz o construtor factory sempre retornar a mesma.
class MySingleton {
// 🔹 Instância única criada logo na inicialização
static final MySingleton _instance = MySingleton._internal();
// 🔹 Construtor factory que retorna sempre a mesma instância
factory MySingleton() {
return _instance;
}
// 🔹 Construtor privado (ninguém fora da classe pode usar)
MySingleton._internal();
// 🔹 Atributos e métodos normais
int counter = 0;
void increment() {
counter++;
print('Contador: $counter');
}
}
Uso:
final a = MySingleton();
final b = MySingleton();
print(identical(a, b)); // true ✅ (mesma instância)
💡 Essa é exatamente a estrutura que usamos no BannerAdManager.
🧱 2. ✅ Com static get instance (forma alternativa mais explícita)
Às vezes, para deixar o código mais legível, você pode preferir usar um getter estático:
class MySingleton {
MySingleton._(); // construtor privado
static final MySingleton _instance = MySingleton._();
static MySingleton get instance => _instance;
void hello() => print('Olá do singleton!');
}
Uso:
MySingleton.instance.hello();
📘 É o mesmo conceito, só muda a sintaxe (e muitos acham mais claro).
⚙️ 3. 🧠 Com inicialização sob demanda (lazy singleton)
Se a criação da instância for “cara” (demorada ou pesada), você pode criar só quando for realmente usada:
class MySingleton {
static MySingleton? _instance;
MySingleton._();
static MySingleton get instance {
_instance ??= MySingleton._(); // cria só na primeira vez
return _instance!;
}
void sayHi() => print('Oi!');
}
Uso:
MySingleton.instance.sayHi();
💡 Ideal se o objeto só for usado em certos momentos do app.
🚀 4. Com injeção de dependência (GetIt, Provider, Riverpod)
Em apps grandes, o singleton geralmente é gerenciado por um container de dependências. Por exemplo, com o GetIt:
import 'package:get_it/get_it.dart';
final getIt = GetIt.instance;
class ApiService {
void fetch() => print('Buscando dados...');
}
void setup() {
getIt.registerLazySingleton<ApiService>(() => ApiService());
}
void main() {
setup();
final api = getIt<ApiService>();
api.fetch(); // ✅ sempre a mesma instância
}
✅ Vantagem: você centraliza todos os singletons e pode trocar implementações em testes (mock).
💡 Dica prática
- Use o padrão clássico (
factory) para gerenciadores pequenos, comoBannerAdManager,UserSession,ConfigService. - Use GetIt ou Riverpod se o app tiver muitas dependências globais.
- Nunca use
staticpuro com variáveis mutáveis expostas — prefira encapsular tudo dentro de uma classe singleton.
🎯 Resumo
| Tipo | Exemplo | Quando usar |
|---|---|---|
factory + _internal() | MySingleton() | Padrão mais comum e direto |
static get instance | MySingleton.instance | Mais explícito e legível |
| Lazy singleton | cria sob demanda | Quando inicialização é pesada |
| GetIt / Provider / Riverpod | via injeção | Apps médios/grandes com várias dependências |