Vamos continuar a série “Padrões de DI” mostrando outra forma de injetar dependências, conhecida por Property Injection. Seguimos os mesmos moldes do post anterior, trazendo a definição do padrão, quando usá-lo e como implementá-lo.

1. O QUE É

Property Injection – também chamado de Setter Injection – é um padrão de DI onde a dependência é fornecida por meio de uma propriedade com o setter público (ou ainda por meio de um setter method).

2. QUANDO USAR

Ao contrário de Constructor Injection, Property Injection é melhor utilizado quando a dependência é opcional e, além disso, a classe consumidora possui uma opção default (*) para a dependência.

(*) Mark Seemann, em seu livro de DI, chama esta opção de local default, por se tratar de uma dependência que, por coesão, encontra-se no mesmo assembly da classe consumidora.

3. COMO IMPLEMENTAR

Vejamos como fica a implementação mais básica do padrão:

public class Funcionario
{
   // setter público para que a dependência possa
   // ser alterada
   public ICalculadorDeBonus Calculador { get; set; }

   public Funcionario()
   {
      // "local default" atribuído no construtor
      Calculador = new BonificacaoPadrao();
   }

   // usando a dependência
   public decimal Bonificacao()
   {
      return Calculador.CalcularBonus();
   }
}

Alguns detalhes:

1. Poderíamos, como uma leve variação, ter utilizado um field ao invés da propriedade e ter criado um método para setar a dependência (como void AlterarFormaDeCalculo(ICalculadorDeBonus  novoCalculador)).

2. É recomendado utilizar uma guard-clause – de forma semelhante ao que fizemos para demonstrar o Constructor Injection no post anterior – para evitar que seja atribuido null à dependência.

3. BonificacaoPadrao é um local default, ou seja, uma classe conceitualmente pertencente ao mesmo assembly de Funcionario (neste caso, um assembly que contém entidades do domínio). Se estivéssemos instanciando um DAO, por exemplo, estaríamos ferindo tudo que está sendo discutido nesta série, pois estaríamos acoplando nosso domínio com uma dependência concreta de uma camada mais volátil (no caso, persistência).

4. Notem também que o exemplo faz uso do design pattern Strategy. Para saber mais sobre ele, dê uma lida <nesse meu outro artigo>.

4. PODE FICAR MAIS COMPLEXO

Pode haver necessidades que exijam uma implementação mais robusta do padrão.

Por exemplo, se necessitarmos que a dependência, após “setada”, não seja mais alterada durante todo o ciclo de vida do objeto, seremos obrigados a adicionar mais uma guard-clause no setter para evitar uma nova atribuição.

Poderíamos também ter que tratar thread-safety, caso houvesse código concorrente acessando o objeto e tentando setar a dependência ao mesmo tempo.

5. CONCLUSÃO

Usamos Property Injection quando a dependência for opcional e tivermos um local default definido.

Sua implementação pode ser mais complexa do que a implementação do padrão Constructor Injection e devemos estar mais atentos para não cairmos em uma cilada.

Até agora, vimos nesta série as duas formas mais comuns de se injetar dependências. Nos próximos posts, falaremos de outros padrões mais incomuns.

Posts anteriores da série na tag <dependency injection>.