Entendendo o Padrão de projetos: Strategy
Junho 22, 2008
Antes de mais nada, gostaria de enviar um abraço aos amigos da comunidade do Orkut “Java BR (cmm=19706)” – Pessoal sempre ajudando quem precisa, boas discussões e um bom ponto de divulgação de vagas de emprego na área, etc.
Entendendo o Padrão de projetos: Strategy – por Robson Farias
Um dos ‘design patterns’ mais importantes catalogados é o Strategy. Um padrão que visa a reutilização, organização e flexibilidade de seus algoritmos. Um marco importântissimo no desenvolvimento de software Orientado a Objeto.
Neste ‘post’ tentarei explica-lo, utilizando a linguagem Java para os exemplos.
Duas das principais dicas que esse padrão prega é:
- Programe sempre para interfaces
É importante ressaltar que, neste contexto ‘interface’ não significa apenas aquelas classes abstratas marcadas com a palavra reservada ‘interface’; mas sim para qualquer modelo reutilizável e abstrato, seja explicitamente uma interface ou uma classe abstrata, o que interessa é ser um modelo bem definido de uma abstração.
- Dê preferência a composição ao invés de herança.
Herança te limita a implementações. É-UM neste caso força o futuro de seus objetos serem sempre dependentes das implementações herdadas. – Já composição (TEM-UM), lhe permite desfrutar de coisas como, erhm.. o padrão de projetos Strategy.
Definimos então um problema:
Uma empresa do ramo de vendas pela internet disponibiliza diversos tipos de produtos para vendas on-line, a empresa é famosa por sempre ter os melhores descontos e promoções. Atualmente, o sistema desta empresa trata os produtos com base no seguinte modelo:
package sem.strategy;
import java.math.BigDecimal;
public abstract class Produto {
public BigDecimal desconto() {
return 5;
}
}
Todos os produtos cadastrados, herdam desta classe. O produto que requer um desconto diferente precisa sobre-escrever a função desconto.
Certo dia, o gerente da empresa teve a brilhante idéia de solicitar ao pessoal do desenvolvimento a seguinte melhoria: A empresa passaria a oferecer descontos padrões para diferentes datas especiais, como Natal, Dia das mães, dia dos namorados, etc. – a equipe de desenvolvimento, que não conhecia o padrão Strategy, logo pensou em entupir as funções ‘desconto()’ sobre-escritas nas classes dos Produtos com ‘if´s’ verificando se a data em questão era uma data especial. Obviamente, que, sempre que surgiam novas datas especiais ou se fossem descartadas outras, o código era retrabalhado, alterado, o sistema parava e era re-implantado novamente, o que gerava uma manutenção mais custosa.
Foi então que um novo desenvolvedor, conhecedor do padrão Strategy, sugeriu seu uso neste caso, o que ele fez:
criou uma interface Promocao (QUE SERÁ NOSSA ESTRATÉGIA), e a definiu da seguinte maneira:
package com.strategy;
import java.math.BigDecimal;
public interface Promocao {
BigDecimal desconto();
}
Então, criou diferentes tipos de implementação para esta promoção, sendo elas:
class PromocaoDeNatal implements Promocao {
@Override
public BigDecimal desconto() {
return 10;
}}
class PromocaoDiaDosNamorados implements Promocao {
@Override
public BigDecimal desconto() {
return 15;
}}
class PromocaoQueimaDeEstoque implements Promocao {
@Override
public BigDecimal desconto() {
return 40;
}
}
E então, refatorou a classe abstrata produto assim:
package com.strategy;
import java.math.BigDecimal;
public class Produto {
protected Promocao promocao;public BigDecimal desconto() {
return promocao.desconto();
}
}
Agora, cada produto poderia determinar um tipo de promoção diferente, a qualquer momento (em tempo de execução) ou não. E a cada nova promoção, bastasse criar uma nova implementação e usar.
Exemplo de uma TV determinando sua promoção:
public class Celular extends Produto {
public Celular() {
this.promocao = new PromocaoDeNatal();
}
}
Note que foi usado uma inversão de controle no constructor do Celular, mas também pode ser criado métodos de acesso a variavel de instância para que possa ser encapsulado isso. O ideal mesmo, é que se utilize um container de Injeção de dependências, como o Spring. Explicado em outro artigo.
Concluimos que, o padrão Strategy é util sob famílias de objetos que necessitam de uma estratégia para mudar seu comportamento de forma plugável em tempo de execução.
Obviamente este foi um exemplo simples (desconsiderem o fato d´eu não ter testado os códigos), que poderia ser feito de diversas outras formas (eu usaria Enum particularmente), mas para melhor entendimento por parte do leitor, foi uma boa escolha. Espero que tenham gostado, qualquer coisa, postem aí!
)
UML: http://www.tml.tkk.fi/~pnr/GoF-models/gif/Strategy.gif
Referências: Head First, Design Patterns.
Ficou muito bom, bastante conciso é de facil entedimento, Otimo para quem está começando a ver P.P. e sente algumas dificuldades com definições longas e cheia de arrodeios.
Como foi citado esse padrão tem 2 vantagens interessante que é a praticidade na modificação, assim como a mudança de uma regra de negócio em tempo de execução, o que é fantástico…
o padrão strategy é bem semelhante ao padrão state, quem ficar em dúvida procure estudar o state também.
Abraços!
É, realmente o post é bastante didático, adorei a forma que você explica. Mas ainda há muita obscuridade para começarmos a por em prática os padrões, necessita de muita experiência para começarmos e meter as caras pra escrever sistemas com base nos padrões.