Abstraindo IoC Container Atrás de uma Singleton - fazendo errado?
-
07-07-2019 - |
Pergunta
Geralmente, eu gosto de manter uma aplicação completamente ignorante do contêiner IoC. No entanto eu tenho teve problemas onde eu necessários para acessá-lo. Abstrair a dor que eu usar um Singleton básico. Antes de correr para as montanhas ou puxe a espingarda, que me deixes passar a minha solução. Basicamente, o singleton IoC faz absolutamente nada, ele simplesmente delega para uma interface interna que deve ser passado. Eu descobri isso faz com que trabalham com o Singleton menos doloroso.
Abaixo está o invólucro IoC:
public static class IoC
{
private static IDependencyResolver inner;
public static void InitWith(IDependencyResolver container)
{
inner = container;
}
/// <exception cref="InvalidOperationException">Container has not been initialized. Please supply an instance if IWindsorContainer.</exception>
public static T Resolve<T>()
{
if ( inner == null)
throw new InvalidOperationException("Container has not been initialized. Please supply an instance if IWindsorContainer.");
return inner.Resolve<T>();
}
public static T[] ResolveAll<T>()
{
return inner.ResolveAll<T>();
}
}
IDependencyResolver:
public interface IDependencyResolver
{
T Resolve<T>();
T[] ResolveAll<T>();
}
Eu tive grande sucesso até agora com as poucas vezes que eu usei-o (talvez uma vez a cada poucos projetos, eu realmente prefiro não ter que usar isso em todos), como eu pode injetar qualquer coisa que eu quero: Castle, um Stub , falsificações, etc.
Esta é uma estrada escorregadia? Eu vou correr para possíveis problemas na estrada?
Solução
Eu vi que mesmo implementos Ayende esse padrão no código Rhino Commons, mas eu aconselho a usá-lo sempre que possível. Há uma razão para que o Castelo de Windsor não tem este código por padrão. StructureMap faz, mas Jeremy Miller foi se afastando dele. Idealmente, você deve considerar o próprio recipiente com tanta desconfiança, como qualquer variável global.
No entanto, como uma alternativa, você pode sempre configurar o seu recipiente para IDependencyResolver determinação como uma referência para o seu recipiente. Isso pode parecer loucura, mas é significativamente mais flexível. Basta lembrar a regra de ouro que um objeto deve chamar "novo" ou executar o processamento, mas não ambos. Para "chamada nova" substituir por "resolver uma referência".
Outras dicas
Isso não é realmente uma classe Singleton. Isso é uma classe estática com membros estáticos. E sim que parece ser uma abordagem bem.
Eu acho JP Boodhoo tem até um nome para este padrão. O estática gateway padrão .
Apenas uma nota: padrões e práticas da Microsoft criou um localizador de serviço comum ( http: //www.codeplex. com / CommonServiceLocator ) que a maioria dos grandes recipientes de IoC será implementar no futuro próximo. Você pode começar a usá-lo em vez de seu IDependencyResolver.
BTW:. Esta é a maneira comum de resolver o seu problema e ele funciona muito bem
Tudo depende da utilização. Usando o recipiente assim é chamado o padrão Service Locator. Há casos em que não é um bom ajuste e casos em que se aplicam.
Se você google "padrão de localizador de serviço", você verá um monte de posts dizendo que é um anti-padrão, o que não é. O padrão foi simplesmente demasia (/ abusado).
Para a linha típica de aplicações de negócio você não deve usar SL como você esconder as dependências. Você também tem um outro problema: você não pode gerenciar o estado / vida se você usar o container raiz (em vez de uma de suas vidas)
.Serviço localizador é uma boa opção quando se trata de infra-estrutura. Por exemplo ASP.NET MVC usa Service Locator para ser capaz de resolver todas as dependências para cada controlador.