Strategy Pattern
Olá pessoal, vou falar um pouco sobre Strategy Pattern, é um Design Pattern que ficou famoso depois de ser catalogado pelo GoF (Gang Of Four) formado por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides no livro “Design Patterns: Elements of Reusable Object-Oriented Software”.
Segue abaixo a definição de acordo com o livro:
“Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.”
Vamos ao exemplo para ficar mais claro a definição.
Imagina que você precisa desenvolver uma funcionalidade que irá validar um usuário. Este é um cenário bem simples e típico podemos fazer esta implementação de várias formas diferentes, abaixo segue um código que em um primeiro momento acho que seria o mais comum.
A primeira classe é uma controller do asp.net mvc que terá uma action que irá receber o usuário e a senha por POST e chamar a classe que irá validar estas informações.
1 | public class LoginController : Controller { |
A classe abaixo será responsável por controlar o fluxo de validação do usuário.
1 | public class UserApplication { |
Nossa classe que será responsável por manipular os dados do usuário.
1 | public class UserDAO { |
Como mencionado acima, este é um código bem simples, porém, este código é impossível testar unitariamente e caso haja a necessidade de alterar a fonte dos dados também será difícil.
Para resolver este problema, podemos aplicar o Strategy Pattern, de forma que iremos passar para a classe UserApplication a “estratégia” (classe) de acesso a dados que iremos utilizar, assim fica fácil testar a classe UserApplication unitariamente e de mudar a fonte de dados quando necessário.
1 | public class UserApplication { |
Notem que agora eu passo a dependência do repositório no construtor da minha classe UserApplication, sendo assim eu consigo passar qualquer classe que implemente a classe IUserDAO.
Abaixo notem que a nossa classe UserDAO sofreu uma modificação, agora ela implementa a interface IUserDAO sendo assim eu posso passar ela no construtor da nossa classe UserApplication.
1 | public interface IUserDAO { |
Vocês podem perceber que agora estou passando para a classe UserApplication a conexão que ela deverá utilizar. Esta classe de conexão é uma “estratégia” que estou utilizando para acessar as informações do usuário, caso haja necessidade de acessar as informações de outra fonte de dados é necessário apenas implementar outra “estratégia” (classe) que implemente a interface IUserDAO e passar para a nossa classe UserApplication como mencionado acima.
1 | public class LoginController : Controller { |
Abaixo outra “estratégia” (classe) de acesso a dados que irá conter os métodos que simulará as operações na base de dados, nos ajudando assim a testar a classe UserApplication.
1 | public class FakeUserDAO : IUserDAO { |
O teste abaixo é para garantir que as operações da classe UserApplication estão de acordo com as regras do negócio.
1 | [ ] |
Analisando a definição do pattern, descrita no inicio do post:
O contexto é a classe UserApplication.
As estratégias criadas foram as classes que implementam a interface IUserDAO no caso a classe UserDAO e FakeUserDAO.
E os clientes que utilizam a classe UserApplication são os testes da classe UserApplication e a action da LoginController.
Neste post usei os seguintes pacotes: Sharp Tests Ex e NUnit.
Existem outras aplicações mais comuns para o Strategy Pattern como: criptografias, logs entre outros cenários, escolhi este cenário também para demonstrar a aplicação de testes unitários em códigos “legados”.
Espero que tenham gostado do exemplo e até a próxima.