Usando o Dagger para injeção de dependência em construtores
Então, atualmente estou redesenhando um aplicativo Android meu para usarPunhal. Meu aplicativo é grande e complicado, e recentemente me deparei com o seguinte cenário:
O objeto A requer uma instância especial do DebugLogger, que é um candidato perfeito para injeção. Em vez de passar em torno do logger, posso apenas injetá-lo através do construtor de A. Isso é algo como isto:
class A
{
private DebugLogger logger;
@Inject
public A(DebugLogger logger)
{
this.logger = logger;
}
// Additional methods of A follow, etc.
}
Até agora isso faz sentido. No entanto, A precisa ser construído por outra classe B. Múltiplas instâncias de A devem ser construídas, então seguindo a maneira de Dagger de fazer as coisas, eu simplesmente informo umaProvider<A>
em B:
class B
{
private Provider<A> aFactory;
@Inject
public B(Provider<A> aFactory)
{
this.aFactory = aFactory;
}
}
Ok, bom até agora. Mas espere, de repente A precisa de entradas adicionais, como um inteiro chamado "quantidade" que é vital para sua construção. Agora, meu construtor para A precisa ficar assim:
@Inject
public A(DebugLogger logger, int amount)
{
...
}
De repente, esse novo parâmetro interfere na injeção. Além disso, mesmo que isso funcionasse, não haveria maneira de passar "quantidade" ao recuperar uma nova instância do provedor, a menos que eu esteja enganado. Há várias coisas que eu poderia fazer aqui, e minha pergunta é qual é a melhor?
Eu poderia refatorar A adicionando umsetAmount()
método que se espera que seja chamado após o construtor. Isso é feio, no entanto, porque me obriga a atrasar a construção de A até que "quantidade" tenha sido preenchida. Se eu tivesse dois parâmetros, "quantidade" e "frequência", então eu teria dois setters, o que significaria verificação complicada para garantir que a construção de A seja retomada depois que ambos os setters forem chamados, ou eu teria que adicionar ainda um terceiro método na mistura, da seguinte forma:
(Somewhere in B):
A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();
A outra alternativa é que eu não uso injeção baseada em construtor e uso injeção baseada em campo. Mas agora tenho que tornar meus campos públicos. Isso não é bom para mim, porque agora sou obrigado a revelar dados internos de minhas aulas para outras classes.
Até agora, a única solução relativamente elegante que consigo pensar é usar injeção baseada em campo para provedores, da seguinte forma:
class A
{
@Inject
public Provider<DebugLogger> loggerProvider;
private DebugLogger logger;
public A(int amount, int frequency)
{
logger = loggerProvider.get();
// Do fancy things with amount and frequency here
...
}
}
Mesmo assim, não tenho certeza sobre o momento, já que não tenho certeza se Dagger vai injetar o provedor antes que meu construtor seja chamado.
Existe uma maneira melhor? Estou apenas sentindo falta de algo sobre como Dagger funciona?