EntLib (parte 5) – Unity Application Block
Aproveitando o embalo do meu post dessa semana sobre o padrão de injeção de dependência, vamos ver o bloco da Enterprise Library responsável por prover essa funcionalidade, chamado Unity Application Block. Criado inicialmente como um projeto separado no CodePlex foi incorporado a Enterprise Library na versão 4.0.
No exemplo de código abaixo a classe Servico utiliza a classe TraceSourceLogger para registrar os passos executados na inicialização e paralização, ou seja, a classe Servico conhece e depende da classe concreta TraceSourceLogger.
public class Servico
{
private TraceSourceLogger logger;
public Servico()
{
logger = new TraceSourceLogger("Agent");
}
public void Iniciar()
{
logger.Log("Iniciando serviço...", System.Diagnostics.TraceEventType.Information);
// Código de inicialização do serviço...
logger.Log("Serviço iniciado.", System.Diagnostics.TraceEventType.Information);
}
public void Parar()
{
logger.Log("Parando serviço...", System.Diagnostics.TraceEventType.Information);
// Código de parada do serviço...
logger.Log("Serviço parado.", System.Diagnostics.TraceEventType.Information);
}
}
O problema aqui é que qualquer alteração na forma de realizar o log da operação implicaria em alterações na classe Servico. Por exemplo, se quiséssemos substituir a classe TraceSourceLogger por outra que realizasse a operação gravando no Event Viewer teríamos que realizar a alteração na classe Servico, inclusive recompilando o projeto.
Uma boa prática aqui é fazer com que ao invés de instanciarmos diretamente a classe concreta o fizéssemos através de uma interface, conforme ilustrado no diagrama a seguir:
Em seguida utilizamos o Unity para resolver as chamadas às classes concretas da seguinte forma. Primeiro adicionamos no arquivo de configuração do projeto as configurações abaixo:
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<typeAliases>
<typeAlias
alias="ILogger"
type="Reverb.Loggers.ILogger, Reverb.DI" />
<typeAlias
alias="ConsoleLogger"
type="Reverb.Loggers.ConsoleLogger, Reverb.DI" />
<typeAlias
alias="TraceSourceLogger"
type="Reverb.Loggers.TraceSourceLogger, Reverb.DI" />
<typeAlias
alias="EventViewerLogger"
type="Reverb.Loggers.EventViewerLogger, Reverb.DI" />
</typeAliases>
<containers>
<container>
<types>
<type type="ILogger" mapTo="TraceSourceLogger" />
</types>
</container>
</containers>
</unity>
</configuration>
No arquivo acima indicamos quais os tipos desejados e como o container deve resolver a implementação concreta para a interface ILogger. Depois, alteraríamos a classe Servico conforme exemplo a seguir:
public class Servico
{
private IUnityContainer container;
private UnityConfigurationSection section;
private ILogger logger;
public Servico()
{
container = new UnityContainer();
section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
logger = container.Resolve<ILogger>();
}
public void Iniciar()
{
logger.Log("Iniciando servico...", System.Diagnostics.TraceEventType.Information);
// Código de inicialização do serviço...
logger.Log("Servico iniciado.", System.Diagnostics.TraceEventType.Information);
}
public void Parar()
{
logger.Log("Parando servico...", System.Diagnostics.TraceEventType.Information);
// Código de parada do serviço...
logger.Log("Servico Parado.", System.Diagnostics.TraceEventType.Information);
}
}
Note que no código acima não definimos em momento algum qual seria a implementação da classe concreta que realiza a operação de log, pois isso fica a cargo do container do Unity que resolverá essa dependência de acordo com o que definimos no arquivo de configuração da classe.
Se quiséssemos agora alterar a implementação de classe concreta que resolveria o log bastaria modificar no arquivo de configuração, como no exemplo a seguir:
<containers>
<container>
<types>
<type type="ILogger" mapTo="ConsoleLogger" />
</types>
</container>
</containers>
Bem fácil, não? Na revista .net Magazine edição 62 terá um artigo meu sobre Injeção de Dependência com o Unity Application Block, colocarei mais informações aqui na próxima semana, aguardem!
Até o próximo post.