Esse post será o início de uma série o qual vou tentar explicar os padrões de projeto utilizando as novidades do Java 8, se visitou esse assunto espero que já conheça os conceitos de orientação a objetos, a linguagem java e Padrões de Projeto.

“O conceito de estratégia, em grego strateegia, em latim strategi, em francês stratégie…”

Capitão Nascimento (Filme Tropa de Elite).

Strategy

É um padrão comportamental utilizado quando uma classe possui muitos algoritmos que tem o mesmo propósito e que podem ser alternados na lógica da aplicação. A execução do algoritmo fica sob responsabilidade de uma instância que compõe a classe principal.

Diagrama do projeto de exemplo utilizando o padrão Strategy

Aplicabilidade

Use o padrão Strategy quando:

  • muitas classes relacionadas diferem somente no seu comportamento. As estratégias fornecem uma maneira de configurar uma classe comum dentre muitos comportamentos;

  • você necessita de variantes de um algoritmo. Por exemplo, pode definir algoritmos que refletem diferentes soluções de compromisso entre espaço/tempo. As estratégias podem ser usadas quando essas variantes são implementadas como uma hierarquia de classes de algoritmos;

  • um algoritmo usa dados dos quais os clientes não deveriam ter conhecimento. Use o padrão Strategy para evitar a exposição das estruturas de dados complexas, específicas do algoritmo;

  • uma classe define muitos comportamentos, e estes aparecem em suas operações como múltiplos comandos condicionais da linguagem. Em vez de usar muitos comandos condicionais, mova os ramos condicionais relacionados para a sua própria classe Strategy.

Implementação

Para exemplo criei uma classe AgenteSecreto que irá consumir os algoritmos de estratégia, possui um método que executa a ação (no caso combater) e outro método que muda a estratégia em tempo de execução:

public class AgenteSecreto {

    private EstrategiaAgente estrategia;

    public AgenteSecreto(EstrategiaAgente estrategia) {
        this.estrategia = estrategia;
    }

    public void mudarEstrategia(EstrategiaAgente estrategia) {
        this.estrategia = estrategia;
    }

    public void combater() {
        estrategia.executar();
    }

}

A interface que define o algoritmo de execução:

public interface EstrategiaAgente {

    public void executar();

}

Criei três implementações da interface com os algoritmos: EstrategiaEngenharia, EstrategiaLinhaDeFrente e EstrategiaSuporte. Agora vamos a Implementação do programa.

Antes do Java 8

Após definir a interface que encapsula o algoritmo só precisamos instanciar a estratégia que queremos utilizar, passando por construtor para a classe AgenteSecreto ou chamando o método mudarEstrategia():

LOGGER.info("Inimigos localizados dentro do forte!");
        AgenteSecreto agente=new AgenteSecreto(new EstrategiaLinhaDeFrente());
        agente.combater();

        LOGGER.info("Inimigos efetuando disparos!");
        agente.mudarEstrategia(new EstrategiaEngenharia());
        agente.combater();

        LOGGER.info("Equipe sendo alvejada!");
        agente.mudarEstrategia(new EstrategiaSuporte());
        agente.combater();

Após o Java 8

A partir do Java 8 e o suporte a programação funcional, podemos utilizar novas sintaxes para alterar os algoritmos.

Lambdas

Com o suporte a Lambdas, podemos “passar” a implementação do algoritmo diretamente para o construtor de AgenteSecreto ou ao método mudarEstrategia():

LOGGER.info("Java 8 Lambdas");
        LOGGER.info("Inimigos localizados dentro do forte!");
        agente=new AgenteSecreto(()->LOGGER.info("Segurar escudo e invadir."));
        agente.combater();

        LOGGER.info("Inimigos efetuando disparos!");
        agente.mudarEstrategia(()->LOGGER.info("Armar torreta, jogar granadas de efeito e plantar minas."));
        agente.combater();

        LOGGER.info("Equipe sendo alvejada!");
        agente.mudarEstrategia(()->LOGGER.info("Esperar feridos e ajudar."));
        agente.combater();

A vantagem dessa abordagem é de não termos que criar uma classe para algoritmos pequenos, diminuindo o número de classes do projeto.

Referência a métodos

Outra facilidade da programação funcional do Java 8 é o de referenciar métodos ou o chamado Method Reference, essa facilidade é interessante quando a expressão lâmbda chama métodos já existentes, para exemplo criei em cada implementação de estratégia um método estático que realiza em si a ação requerida, com isso é possível utilizar a sintaxe do method reference e “passar” os métodos diretamente para o AgenteSecreto:

LOGGER.info("Java 8 Method References");
        LOGGER.info("Inimigos localizados dentro do forte!");
        agente.mudarEstrategia(EstrategiaLinhaDeFrente::combaterComoLinhaDeFrente);
        agente.combater();

        LOGGER.info("Inimigos efetuando disparos!");
        agente.mudarEstrategia(EstrategiaEngenharia::combaterComoEngenheiro);
        agente.combater();

        LOGGER.info("Equipe sendo alvejada!");
        agente.mudarEstrategia(EstrategiaSuporte::combaterComoSuporte);
        agente.combater();

Essa abordagem é interessante para os casos em que temos expressões lambda que apenas chamam outros métodos. Com ela deixamos o código mais legível além de chamarmos diretamente o método de ação.

Executando

Ao executarmos a aplicação temos o seguinte resultado:


padroes.strategy.Aplicacao - Inimigos localizados dentro do forte!
padroes.strategy.EstrategiaLinhaDeFrente - Segurar escudo e invadir.
padroes.strategy.Aplicacao - Inimigos efetuando disparos!
padroes.strategy.EstrategiaEngenharia - Armar torreta, jogar granadas de efeito e plantar minas.
padroes.strategy.Aplicacao - Equipe sendo alvejada!
padroes.strategy.EstrategiaSuporte - Esperar feridos e ajudar.
padroes.strategy.Aplicacao - Java 8 Lambdas
padroes.strategy.Aplicacao - Inimigos localizados dentro do forte!
padroes.strategy.Aplicacao - Segurar escudo e invadir.
padroes.strategy.Aplicacao - Inimigos efetuando disparos!
padroes.strategy.Aplicacao - Armar torreta, jogar granadas de efeito e plantar minas.
padroes.strategy.Aplicacao - Equipe sendo alvejada!
padroes.strategy.Aplicacao - Esperar feridos e ajudar.
padroes.strategy.Aplicacao - Java 8 Method References
padroes.strategy.Aplicacao - Inimigos localizados dentro do forte!
padroes.strategy.EstrategiaLinhaDeFrente - Segurar escudo e invadir.
padroes.strategy.Aplicacao - Inimigos efetuando disparos!
padroes.strategy.EstrategiaEngenharia - Armar torreta, jogar granadas de efeito e plantar minas.
padroes.strategy.Aplicacao - Equipe sendo alvejada!
padroes.strategy.EstrategiaSuporte - Esperar feridos e ajudar.

Vantagens e desvantagens do Strategy

Em outras fontes você irá encontrar diversas vantagens e desvantagens sobre o padrão, para mim as principais vantagens são:

  • criar novos algoritmos com modificações mínimas da aplicação;
  • poder alterar os algoritmos em tempo de execução;
  • diminuição de estruturas condicionais na classe cliente.

Já as desvantagens:

  • aumento no número de classes;
  • aumento na complexidade de criação do objeto, já que a instância da dependência precisa ser criada e configurada.

Finalizando

Na versão 8 a linguagem Java trouxe ótimas novidades que ajudam bastante no desenvolvimento de soluções de código mais simples e legíveis. O suporte a programação funcional trás um novo paradigma para os desenvolvedores que utilizam a linguagem, cabe a nós avaliar e escolher a melhor forma de aproveitá-la. Um forte abraço e até a próxima.

Código no Github

https://github.com/ivanqueiroz/padroes-projeto-java

Créditos