3
respostas

Como instanciar objetos Strategy

Olá.

Considere a implementação básica do padrão Strategy.

public class Context{
  private Strategy strategy;
}

public interface Strategy{
  void algoritmo();
}

public class ConcreteStrategyA implements Strategy{
  void algoritmo(){
    // algoritmo A
  }
}

public class ConcreteStrategyB implements Strategy{
  void algoritmo(){
    // algoritmo B
  };

A dúvida refere-se ao seu uso, ou seja, como instanciar os objetos ConcreteStrategyA e ConcreteStrategyC?

Penso na seguintes alternativa: crio o objeto, em uma camada de controle, por exemplo, e repasso para a classe Context, na qual invoca o método (polimórfico algoritmo();). Mas como saber qual o objeto correto instanciar? Teria que fazer uma lógica (uso de if/ else) para identificar o objeto correto. Mas dessa forma, fazendo uso de estruturas de condição, eu estaria criando um problema que o padrão Strategy procura resolver. Correto?

Para deixar mais claro, suponha o seguinte cenário: possuo uma classe CalculadoraDeTarifas (Context), ela recebe o tipo de veiculo(carro, moto, etc) e um periodo de tempo. Suponha ainda que tenho um Strategy TarifaStrategy que é a interface para DiariaMoto, DiariaCarro, PorHoraMoto, PorHoraCarro, MensalidadeMoto, MensalidadeCarro, etc.

Considere agora que preciso passar que uma moto permaneceu por um período de 15 horas. Nesse caso, como uma das regras é que, quando o período for superior a 12 horas é cobrado uma "Diária", para moto. Esse cálculo deveria estar no algoritmo() de DiariaMoro, correto? Se sim, como fazer com que ele seja executado?

Desculpe se não fui claro suficiente.

Obrigado.

3 respostas

Fala William, tudo bem?

[...] Mas dessa forma, fazendo uso de estruturas de condição, eu estaria criando um problema que o padrão Strategy procura resolver. Correto?

Exato.

Se sim, como fazer com que ele seja executado?

Se DiariaMoto implementa a interface Strategy, então você poderá fazer strategy.algoritmo() sem se preocupar com quem é de fato a instância referenciada por strategy.

Segue um artigo interessante sobre o assunto: https://medium.com/collabcode/strategy-padr%C3%B5es-de-projeto-em-java-43889a3afc5a

Abraço!

Olá.

Sim, entendo perfeitamente isso. Afinal esse é o propósito do polimorfismo que é base para tudo.

O foco é: em algum momento terei que criar um objeto. Onde e como criar esse objeto.

Receio que não terei como fugir de uma estrutura de condição, mesmo usando factorys. É necessário ter uma lógica para que, em tempo de execução, a escolha do objeto seja feita apropriadamente.

A maioria dos exemplos que vemos por aí é a explicação do padrão com exemplos de utilização de forma didática, como por exemplo, a criação dos objetos no main().

Veja isso:

main(){

//Strategy strategy = new DiariaMoto(x, y);
Strategy strategy = new DiariaVeiculo(x, y);

strategy.algoritmo();

}

Nesse caso, eu escolhi, em tempo de projeto, qual objeto instanciar.

Agora, veja essa ideia:

main(){

Strategy strategy = Factory.calcularDiaria(Veiculo v, Tempo t);

strategy.algoritmo();

}

Dentro da Factory.calcularDiaria teria que ter uma estrutura de condição para escolher qual objeto criar, se uma diaria de moto, se uma diaria de carro, se mensalidade de carro, etc

Nesse caso, retorno ao inicio do problema: fazendo uso de estruturas de condição, eu estaria criando o mesmo problema.

Veja que no site indicado o objeto é criado, ele é escolhido, e passado como parâmetro. Poderia fazer isso - escolher o objeto e passá-lo juntamento com o tempo. Pensando melhor, vejo que terie que escolher qual o veículo de qualquer forma, o que vai mudar é o tempo, pois, conforme as regras, pode ser cobrado, por dia, por mes, etc.

Estou chegando a conclusão que dessa forma não poderei evitar estruturas de decisão, talvez mais simples, mas com elas.

Obrgado.

oI Willian

Mas dessa forma, fazendo uso de estruturas de condição, eu estaria criando um problema que o padrão Strategy procura resolver. Correto?

Sim!

Considere agora que preciso passar que uma moto permaneceu por um período de 15 horas. Nesse caso, como uma das regras é que, quando o período for superior a 12 horas é cobrado uma "Diária", para moto. Esse cálculo deveria estar no algoritmo() de DiariaMoro, correto? Se sim, como fazer com que ele seja executado?

Sim, cada classe concreta tem um comportamento parecido que deve variar, a interface definirá o contrato que as classes concretas devem implementar mediante esse contrato eu sei que aquela estratégia faz sentido pro meu contexto, assim como outros padrões o strategy precisa ser configurado inicialmente ele começa com uma estratégia inicial que pode variar em tempo de execução.Toda essa configuração fica no Context você pode fazer isso no próprio construtor e criar um método do tipo setContext(Strategy strategy) para alternar entre as estratégias. O Strategy e Context interagem para implementar o algoritmo escolhido. um exemplo bem simples se encontra no livro Head First Design Patterns o clássico exemplo dos Patos:

public abstract class Duck {
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;

    public Duck() {
    }

    public void setFlyBehavior (FlyBehavior fb) {
        flyBehavior = fb;
    }

    public void setQuackBehavior(QuackBehavior qb) {
        quackBehavior = qb;
    }

    abstract void display();

    public void performFly() {
        flyBehavior.fly();
    }

    public void performQuack() {
        quackBehavior.quack();
    }

    public void swim() {
        System.out.println("All ducks float, even decoys!");
    }
}

Perceba que na minha classe contexto eu tenho referencias para famílias de algoritmos, e posso alternar entre elas em tempo de execução através dos métodos setFlyBhavior e setQuackBehaviour. Ainda temos um método que executa a estratégia no caso os métodos performFly.

Espero ter ajudado e bons estudos.