Padrão de Projeto de Estratégia
Digamos que temos um aplicativo que permite aos clientes pagar pela compra de um produto ou pela obtenção de um serviço.
O aplicativo possui mais de uma forma de pagamento, o cliente pode usar dinheiro, cartão visa ou carteira, podemos fazer assim:
public class Customer {
public void pay(String paymentType) {
if (StringUtils.isEmpty(paymentType)) {
throw new RuntimeException("please add payment method");
}
// pay according to payment type
if (paymentType.equalsIgnoreCase("cash")) {
// pay in cash steps ( Algorithm )
} else if (paymentType.equalsIgnoreCase("visa")) {
// use the visa for payment steps ( Algorithm )
} else if (paymentType.equalsIgnoreCase("wallet")) {
// use the wallet for payment steps ( Algorithm )
} else {
throw new RuntimeException(paymentType + "payment type is not available");
}
}
}
public class Client {
public static void main(String[] args) {
Customer customer = new Customer();
customer.pay("cash");
}
}
Na verdade não,
- Se você quiser adicionar um novo método de pagamento, precisará alterar esta classe e isso torna seu design não flexível para novas alterações. Com essa implementação, violamos um dos princípios de design do SOLID, que é: “ as entidades de software devem ser abertas para extensão, mas fechado para modificação ”
- A maior parte da lógica da classe não é usada, uma vez que o tipo de pagamento é escolhido pelo cliente, portanto, se o cliente quiser pagar em dinheiro, o código que lida com visa e wallet não será usado.
- Como você vê nesta forma de design, você deve lidar com todas as entradas de tipo de pagamento possíveis, mesmo que não façam sentido, como um tipo de pagamento NULL ou tipo de pagamento vazio, e você pode facilmente restringir o cliente a escolher apenas tipos de pagamento válidos , usando um padrão de estratégia.
Temos três tipos de pagamento e em cada caso existe uma implementação diferente então temos um comportamento “pagar” com formas diferentes, então o que poderia acontecer se pegássemos o que varia e colocássemos em classes separadas e usássemos uma interface comum para o comportamento comum .
Vamos criar uma interface chamada Payment . Terá um método abstrato, e cada método de pagamento tem sua classe concreta que implementa a interface Payment . O Cliente terá a interface de pagamento como uma variável “composição de uso” e o tipo de método será decidido pela escolha do cliente.
public interface Payment {
void pay();
}
public class CashPayment implements Payment {
@Override
public void pay() {
// pay in cash steps ( Algorithm )
}
}
public class VisaPayment implements Payment {
@Override
public void pay() {
// use the visa for payment steps ( Algorithm )
}
}
public class WalletPayment implements Payment {
@Override
public void pay() {
// use the wallet for payment steps ( Algorithm )
}
}
public class Customer {
private Payment payment;
public Customer(Payment payment) {
this.payment = payment;
}
public void setPaymentType(Payment payment) {
this.payment = payment;
}
public void pay() {
payment.pay();
}
}
public class Client {
public static void main(String[] args) {
Customer customer = new Customer(new VisaPayment());
customer.pay();
// you can change the payment type at runtime
customer.setPaymentType(new CashPayment());
customer.pay();
}
}

Princípios de design
da discussão anterior, podemos concluir quatro princípios de design:
- Design para uma interface não para implementação
- Encapsule o que varia
- As entidades de software devem estar abertas para extensão, mas fechadas para modificação
- Use composição sobre herança
A definição do livro para o padrão de estratégia é: Definir uma família de algoritmos, encapsular cada um e torná-los intercambiáveis. A estratégia permite que o algoritmo varie independentemente dos clientes que o utilizam.
No nosso exemplo a família de algoritmos eram os métodos de pagamento, e encapsulamos cada um deles na subclasse concreta, e são intercambiáveis pelo cliente que pode escolher qualquer tipo de pagamento mesmo em tempo de execução, o algoritmo é separado do Cliente e do Cliente …. e esse é o padrão de estratégia .