Injeção de campo é um pouco "ação assustadora à distância" para o meu gosto.
Considere o exemplo que você forneceu na sua postagem do Grupos do Google:
public class VeracodeServiceImplTest {
@Tested(fullyInitialized=true)
VeracodeServiceImpl veracodeService;
@Tested(fullyInitialized=true, availableDuringSetup=true)
VeracodeRepositoryImpl veracodeRepository;
@Injectable private ResultsAPIWrapper resultsApiWrapper;
@Injectable private AdminAPIWrapper adminApiWrapper;
@Injectable private UploadAPIWrapper uploadApiWrapper;
@Injectable private MitigationAPIWrapper mitigationApiWrapper;
static { VeracodeRepositoryImpl.class.getName(); }
...
}
Então, basicamente, o que você está dizendo é que "tenho essa classe com estado privado, à qual anexei as anotações @injectable
, o que significa que o estado pode ser preenchido automaticamente por algum agente externo, mesmo que meu estado foi tudo declarado privado. "
Eu entendo as motivações para isso. É uma tentativa de evitar grande parte da cerimônia que é inerente à criação de uma aula corretamente. Basicamente, o que se está dizendo é que "estou cansado de escrever todo esse clichê, então vou anotar todo o meu estado e deixar que o contêiner DI cuide de configurá-lo para mim".
É um ponto de vista perfeitamente válido. Mas também é uma solução alternativa para recursos de linguagem que, indiscutivelmente, não devem ser contornados. Além disso, por que parar aí? Tradicionalmente, o DI conta com cada classe tendo uma interface complementar. Por que não eliminar todas essas interfaces com anotações também?
Considere a alternativa (isso será C #, porque eu sei disso melhor, mas provavelmente há um equivalente exato em Java):
public class VeracodeService
{
private readonly IResultsAPIWrapper _resultsApiWrapper;
private readonly IAdminAPIWrapper _adminApiWrapper;
private readonly IUploadAPIWrapper _uploadApiWrapper;
private readonly IMitigationAPIWrapper _mitigationApiWrapper;
// Constructor
public VeracodeService(IResultsAPIWrapper resultsApiWrapper, IAdminAPIWrapper adminApiWrapper, IUploadAPIWrapper uploadApiWrapper, IMitigationAPIWrapper mitigationApiWrapper)
{
_resultsAPIWrapper = resultsAPIWrapper;
_adminAPIWrapper = adminAPIWrapper;
_uploadAPIWrapper = uploadAPIWrapper;
_mitigationAPIWrapper = mitigationAPIWrapper;
}
}
Já sei algumas coisas sobre essa aula. É uma classe imutável; estado só pode ser definido no construtor (referências, neste caso particular). E como tudo deriva de uma interface, posso trocar implementações no construtor, que é onde seus mocks aparecem.
Agora, tudo que meu contêiner de DI precisa fazer é refletir sobre o construtor para determinar quais objetos ele precisa para ser instalado. Mas essa reflexão está sendo feita em um membro público, de uma maneira de primeira classe; Ou seja, os metadados já fazem parte da classe, tendo sido declarados no construtor, um método cuja finalidade expressa é fornecer à classe as dependências necessárias.
Com certeza isso é muito padronizado, mas é assim que a linguagem foi projetada. As anotações parecem um truque sujo para algo que deveria ter sido incorporado à própria linguagem.