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: livro Use a Cabeça - Padrões de Projeto, 2a Edição.