sexta-feira, 15 de agosto de 2014

Padrões de Projeto - Strategy

       Padrões de projeto servem para estruturar a forma como os sistemas são construídos de modo a facilitar tanto a própria construção quanto a manutenção. Os padrões de projeto baseiam-se nos princípios de programação e em boas práticas, e se tornaram padrões devido terem sido usados várias vezes e terem alcançado bons resultados. O padrão STRATEGY visa tornar a estrutura do projeto mais flexível, tornando-o mais receptível a mudanças. Ele se baseia em 3 princípios:
  • Programar para interface ao invés de programar para implementação;
  • Separar o que varia do que permanece igual, encapsulando o que varia;
  • Dar preferência a composição do que a herança.
       O livro Use a Cabeça - Padrões de projetos traz um exemplo de um "jogo" que ele categoriza como um simulador de patos, que trabalha com patos de diferentes tipos: patos de verdade, patos de borracha, patos de madeira... e está sujeito a trabalhar com mais tipos de patos diferentes no futuro. A questão é que eles variam seus comportamentos, afinal, patos de madeira não voam nem grasnam, os de borracha fazem barulho, que no entanto não é um grasnar de patos de verdade, e também não voam. E por fim, no futuro ainda podem entrar outros tipos de patos no sistema. Como lidar com a mudança?
       Podemos ver a solução logo abaixo:

       Os comportamentos que pertencem a todos os patos (mostrar o pato na tela e nadar) que pelo menos por enquanto não variam, são métodos comuns (display() e swin()) que não precisaram ser "encapsulados" por uma interface em grupos de algorítimos, podendo o desenvolvedor usar apenas a sobrescrita de métodos dada pela herança caso ache necessário, o que é uma verdade no caso de display(), afinal cada pato tem uma exibição.
       Já os métodos que setam o comportamento de voar e grasnar, como variam em cada tipo de pato, foram "encapsulados" através de uma interface criada para cada um deles (FlyBehavior e QuackBehavior respectivamente). Agora esses comportamentos que compõe o nosso objeto Duck deixaram de ser métodos e passaram a ser variáveis de instância para objetos que implementem a interface FlyBehavior e QuackBehavior.
       Qual a vantagem? Bem, digamos que eu queira criar um pato de plástico, que nada porém não faz barulho, o que eu preciso adicionar de extra? Nada, basta na hora de criar a classe PatoDePlastico fazer ela instanciar a classe FlyNoWay e MuteQuack. E se eu quiser um apito para chamar patos, não posso estender de pato, afinal, não é um pato, mas eu preciso do som de pato, o que fazer? É simples! Basta usar a interface QuackBehavior como fizemos na classe Duck. Ou seja, temos um sistema flexível e expansível.
       Agora um pouco de código para mostrar como essas classes se comunicam:
      
       Como seria o construtor de uma classe que herda de Duck?
public class MallardDuck extends Duck {
       public MallardDuck(FlyBehavior fb, QuackBehavior qb) {
              flyBehavior = fb;
              quackBehavior = qb;
       }...
       O método performFly() e performQuack() da classe Duck respectivamente...
       public void performFly(){
              flyBehavior.fly();
       }
       public void performQuack(){
             QuackBehavior.quack();
       }...
       Agora os métodos da classe Duck que deixam os comportamentos de voar e grasnar dinâmicos... eles devem receber um comportamento como parâmetro.
       public void setFlyBehavior(FlayBehavior fb) {
              flyBehavior = fb;
       }
       public void setQuackBehavior(QuackBehavior qb) {
              quackBehavior = qb;
       }... 
       Pronto, o PADRÃO STRATEGY foi aplicado com sucesso. Veja que nos códigos mostrados, não nos preocupamos com as classes que implementam as interfaces, isso porque abstraímos essas classes encapsulando-as através das interfaces.

Fonte: Baseado no livro Use a Cabeça - Padrões de Projeto, 2a Edição.