CoreLib ObjectFactory Design Reference

Keyworks: ObjectFactory Container Dependency Injection IoC Inversion Control Service Locator SimpleInjector Unity

Introdução

Num produto complexo a instanciação dos objetos pode tornar-se um problema de manutenção porque as dependências tendem a evoluir e é muito fácil introduzir uma quebra. Uma solução é delegar o problema da instanciação para um componente que conhece todos os outros e sabe criar e resolver as suas instâncias.

Desenho

O container deixa de ser o tipo amplamente usado e passa a estar escondido por detrás de uma Façade construída com base nos tipos estáticos e por isso deixa de estar acessível fora dos componentes CoreLib.

A implementação atual usa um container interno implementado usando o SimpleInjector.

Instanciação de Objetos

Para criar objetos simples que não são registados no Container mas que têm interesse em ver as suas dependências iniciadas:

  • ObjectFactory.Get();
CustomerViewModel myViewModel = ObjectFactory.Get<CustomerViewModel>();

Para obter a instância correta de um dado tipo:

  • ObjectFactory.Get();
public property IMyType MyProperty
{
    get
    {
        return ObjectFactory.Get<IMyType>();
    }
}

Registo de Tipos

  • ObjectFactoryConfiguration.Register();
  • ObjectFactoryConfiguration.Register(RegistrationOption.IfMissing, Replace);
  • ObjectFactoryConfiguration.Register(Lifecycle.AlwaysCreateNew, Singleton);

RegistrationOption

Esta opção do registo permite controlar o registo de vários tipos para o mesmo contrato:

  • IfMissing – o registo será efetuado apenas se não existir um anterior para o mesmo contrato.
  • RegisterOrReplace – o registo substituirá um anterior se existir.
  • RegisterMultiple – o registo é incrementado a qualquer outro que já exista para o mesmo tipo. Nesse caso, a resolução deverá ser realizada através do método GetAll.

Lifecycle

Esta opção permite controlar o ciclo de vida da instância concreta devolvida na resolução.

  • AlwaysCreateNew – será devolvida uma nova instância do tipo em cada resolução.
  • Singleton – será devolvida sempre a mesma instância do tipo a cada resolução.

Limitações

  • Dado o desenho do container interno, todos os registos de tipos deve acontecer antes do primeiro Get. Sempre que um registo for invocado depois do primeiro get resolvido, será lançada uma exceção e o registo falhará.
  • O componente não suporta qualquer tipo de mecanismo de registo por convenção. Ou seja, um Get só devolverá um resultado se existir um registo explícito para esse tipo feito anteriormente. Exceto o caso em que o tipo solicitado seja uma classe (não uma interface) porque nesse caso será devolvida uma instância desse mesmo tipo (o que facilita o cenário descrito acima de inicialização de dependências desse tipo).

Configuração

Este componente foi desenhado para ser usado programaticamente. No entanto, é possível incluir no ficheiro de configuração registos de tipos que serão realizados automaticamente no momento em que o componente for ativado pela primeira vez.

Esses registos devem identificar claramente os tipos do contrato e da implementação, usando o assembly qualified name.

Exemplo:

<objectFactoryConfiguration>
  <types>
    <add typeName="Company.Contracts.IYourOtherType, Company.Contracts, Version=3.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256" concreteType="Company.Domain.YourOtherType, Company.Domain, Version=3.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256"/>
  </types>
</objectFactoryConfiguration>

Tracing

O comportamento deste componente pode ser diagnosticado ativando o modo Verbose do componente de Tracing da plataforma.

<tracingConfiguration level="Verbose">

FAQ

  • P: Em que momento é efetuado o registo dos tipos enumerados no ficheiro de configuração?
    • R: Exatamente no primeiro instante em que o componente seja usado, seja através de um ObjectFactoryConfiguration.Register ou através de um ObjectFactory.Get.
  • P: O que acontece se fizer um Get de um tipo não registado?
    • R: Se o tipo for uma interface, será devolvido null ou lançada uma exceção (dependendo de um parâmetro do Get). Se for uma classe será devolvida uma instância dessa mesma classe.