O Padrão de Projeto Strategy define uma família de algoritmos, encapsula cada algoritmo e os torna intercambiáveis, permitindo que o algoritmo varie independente dos clientes que o utilizam.
Essa é uma definição clássica e abstrata. Não se assuste se não entendeu nada. Realmente sem ter um exemplo prático fica muito difícil entender.
A idéia do post é justamente essa. Trazer uma abordagem prática para que o leitor possa de fato absorver e compreender esse padrão.
Imagine a classe documento abaixo:
package sem.strategy;
public abstract class Documento {
public void imprime(){
System.out.println("Documento impresso em Pdf");
}
}
Atualmente está preparada apenas para imprimir documentos em Pdf de forma padrão. Mais surgiu a necessidade de implementar diversos tipos de impressões de documentos, por exemplo: Pdf, Xml, Xls, HTml. E para piorar, a impressão de todos esses documentos pode ser feita de suas formas: com ou sem título.
A primeira idéia que a equipe de desenvolvimento teve foi encher a classe Documento de métodos para cada tipo de impressão. A cada novo método de impressão criado, a classe Documento teria que ser mantida. Outra desvantagem é que certos tipos de documentos poderiam ser impressos de formas diferentes, por exemplo: um documento Jurídico pode ser impresso de forma diferente de um documento Técnico.
Certo desenvolvedor, conhecia e decidiu usar o Padrão de Projeto Strategy (ou Estratégia).
A idéia foi tirar a regra de impressão de dentro da classe Documento, fazendo uso do Strategy.
Dessa forma foi criado a interface Imprime, que será nossa Estratégia, conforme abaixo:
package com.strategy;
public interface Imprime {
public void imprime();
}
Para o nosso exemplo vamos criar apenas duas classes que imprimem, Pdf e Xml:
package com.strategy;
public class Pdf implements Imprime {
@Override
public void imprime() {
System.out.println("Documento foi impresso em PDF!");
}
}
package com.strategy;
public class Xml implements Imprime {
@Override
public void imprime() {
System.out.println("Documento foi impresso em XML!");
}
}
Tivemos que fazem uma pequena alteração na classe Documento, ficando assim:
package com.strategy;
public abstract class Documento {
protected Imprime imprime;
public void imprime(){
imprime.imprime();
}
public void setImprime(Imprime imprime) {
this.imprime = imprime;
}
}
Veja que agora a classe Documento não conhece mais a forma de como o documento é impresso. Como podemos observar o método imprime, apenas faz a chamada ao método imprime da nossa Estratégia (interface) e não faz a menor idéia de como o documento será impresso.
Criamos um documento técnico:
package com.strategy;
public class Tecnico extends Documento {
}
Agora vamos criar uma classe cliente para testar o uso do nosso Padrão de Projeto:
package com.strategy;
public class Cliente {
public static void main(String[] args) {
Documento documento = new Tecnico();
documento.setImprime(new Pdf());
documento.imprime();
documento.setImprime(new Xml());
documento.imprime();
}
}
Rodando esse exemplo, esperamos como saída:
Documento foi impresso em PDF!
Documento foi impresso em XML!
Legal! Como podemos observar a forma como o documento é impressa pode ser alterada em tempo de execução.
