Na verdade, o caminho "certo" é NÃO usar uma fábrica, a menos que não exista outra opção (como nos testes de unidade e em certas simulações - para o código de produção, você NÃO usa uma fábrica)! Fazer isso é realmente um antipadrão e deve ser evitado a todo custo. O objetivo principal de um contêiner de DI é permitir que o gadget faça o trabalho por você.
Conforme mencionado acima em uma postagem anterior, você deseja que seu gadget de IoC assuma a responsabilidade pela criação dos vários objetos dependentes no seu aplicativo. Isso significa deixar seu gadget de DI criar e gerenciar as várias instâncias em si. Esse é o ponto principal da DI - seus objetos NUNCA devem saber como criar e / ou gerenciar os objetos dos quais dependem. Fazer o contrário quebra o acoplamento solto.
Converter um aplicativo existente em todas as DIs é um grande passo, mas deixando de lado as óbvias dificuldades em fazê-lo, você também desejará (apenas para facilitar a sua vida) explorar uma ferramenta de DIs que executará automaticamente a maior parte de suas ligações (o núcleo de algo como o Ninject são as "kernel.Bind<someInterface>().To<someConcreteClass>()"
chamadas que você faz para corresponder suas declarações de interface às classes concretas que deseja usar para implementar essas interfaces. São aquelas chamadas "Vinculadas" que permitem que seu gadget DI intercepte suas chamadas de construtor e forneça o instâncias de objeto dependentes necessárias.Um construtor típico (pseudo-código mostrado aqui) para alguma classe pode ser:
public class SomeClass
{
private ISomeClassA _ClassA;
private ISomeOtherClassB _ClassB;
public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
{
if (aInstanceOfA == null)
throw new NullArgumentException();
if (aInstanceOfB == null)
throw new NullArgumentException();
_ClassA = aInstanceOfA;
_ClassB = aInstanceOfB;
}
public void DoSomething()
{
_ClassA.PerformSomeAction();
_ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
}
}
Observe que em nenhum lugar desse código havia qualquer código que criava / gerenciava / liberava a instância de SomeConcreteClassA ou SomeOtherConcreteClassB. De fato, nenhuma classe concreta foi sequer referenciada. Então ... onde a mágica aconteceu?
Na parte de inicialização do seu aplicativo, ocorreu o seguinte (novamente, esse é um pseudo-código, mas é bem parecido com o real (Ninject) ...):
public void StartUp()
{
kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}
Esse pouco de código diz ao dispositivo Ninject para procurar construtores, varrê-los, procurar instâncias de interfaces que foram configuradas para lidar (que são as chamadas "Bind") e depois criar e substituir uma instância da classe concreta em qualquer lugar a instância é referenciada.
Existe uma boa ferramenta que complementa muito bem o Ninject, chamado Ninject.Extensions.Conventions (outro pacote do NuGet), que fará a maior parte deste trabalho para você. Para não tirar a excelente experiência de aprendizado que você experimentará ao criar isso sozinho, mas para começar, isso pode ser uma ferramenta para investigar.
Se a memória servir, o Unity (formalmente da Microsoft agora um projeto de código aberto) possui uma ou duas chamadas de método que fazem a mesma coisa, outras ferramentas têm ajudantes semelhantes.
Qualquer que seja o caminho que você escolher, leia definitivamente o livro de Mark Seemann para a maior parte do seu treinamento em DI, no entanto, deve-se salientar que mesmo os "Grandes" do mundo da engenharia de software (como Mark) podem cometer erros flagrantes - Mark esqueceu tudo. Ninject em seu livro, então aqui está outro recurso escrito apenas para Ninject. Eu tenho isso e é uma boa leitura: Dominando o Ninject para injeção de dependência