Strategy

Intenção

Definir uma família de algoritmos, encapsular cada uma delas e torná-las intercambiáveis.  
 

Vantagens

Desvantagens

Exemplos

Exemplo #1

O processo de fabricação de carros exige a execução de etapas como produção da carroceria, pintura e montagem dos equipamentos, que resultam em um carro pronto para ser dirigido. Para certos tipos de carro,  algumas dessas etapas exigem implementações específicas: em modelos Hatch, a carroceria é dividia em dois volumes: um para o motor e um para os passageiros e porta-malas, enquanto em modelos Sedan a carroceria é dividida em três volumes: um para o motor, um para os passageiros e um para o porta-malas. Isso significa que uma mesma implementação é irreplicável para ambos os casos. Uma interface Assembler possui as assinaturas dos métodos que realizam a construção de um carro (buildCarBodyWork, paintCar e mountCarParts) enquanto as classes SedanCar e HatchCar implementam Assembler e definem as implementações das operações. Quando é necessário construir, por exemplo, um carro Sedan, a classe Car mantém uma referência para uma instância de SedanCar e dentro do método manufacture executa os métodos de construção.
 

Diagrama de Classe

Exemplo #1 - Diagrama

Participantes

  • Strategy (Assembler) Define uma interface comum para os possíveis algoritmos, sendo usado por Context para chamar o algoritmo definido em uma instância concreta.

  • ConcreteStrategy (SedanCar, HatchCar) Implementa os algoritmos definidos pela interface Strategy.

  • Context (Car) Mantém uma referência para um objeto Strategy.

Código

package strategy;

public class SedanCar implements Assembler {

    // Atributos de Car que serão modificados durante as etapas do algoritmo.
    private String color;
    private int bodyWorkVolumesNumber;
    private String engineType;
    private String tireType;
    private String starterMotorType;

    // Implementações específicas para cada etapa do algoritmo que constrói um carro Hatch
    public void buildCarBodyWork(){
        this.bodyWorkVolumesNumber = 3;
    }

    public void paintCar() {
        this.color = "black";
    }

    public void mountCarParts(){
        this.engineType = "W type";
        this.tireType = "Summer";
        this.starterMotorType = "Planetary Gear";
    }

    public String getCarInfo(){
        return "Number of bodywork volumes: " + this.bodyWorkVolumesNumber
             + "\nCar color: " + this.color
             + "\nEngine type: " + this.engineType
             + "\nTire type: " + this.tireType
             + "\nStarter motor type: " + this.starterMotorType;
    }

}
package strategy;

public class Client {
    public static void main(String[] args) {

        Car car = new Car();

        //Instancia uma classe para a execução de um algoritmo SedanCar e passa essa instância para a instância de Car.
        SedanCar sedanCar = new SedanCar();
        car.setCarAssembler(sedanCar);

        car.manufacture();
    
        System.out.println("Car info:");
        System.out.println(sedanCar.getCarInfo());
    }
}
package strategy;

public class Car {

    private Assembler carAssembler;

    //Método que executa as etapas de Strategy
    public void manufacture(){
        carAssembler.buildCarBodyWork();
        carAssembler.paintCar();
        carAssembler.mountCarParts();
    }

    public void setCarAssembler(Assembler carAssembler) {
        this.carAssembler = carAssembler;
    }
}
package strategy;

public interface Assembler {
    //Definição das operações abstratas executáveis pelo algoritmo
    public abstract void buildCarBodyWork();
    public  abstract void paintCar();
    public abstract void mountCarParts();
}
package strategy;

public class HatchCar implements Assembler {

    // Atributos de Car que serão modificados durante as etapas do algoritmo.
    private String color;
    private int bodyWorkVolumesNumber;
    private String engineType;
    private String tireType;
    private String starterMotorType;

    // Implementações específicas para cada etapa do algoritmo que constrói um carro Hatch
    public void buildCarBodyWork(){
        this.bodyWorkVolumesNumber = 2;
    }

    public void paintCar() {
        this.color = "blue";
    }

    public void mountCarParts(){
        this.engineType = "V type";
        this.tireType = "All Season";
        this.starterMotorType = "Direct Drive";
    }

    public String getCarInfo(){
        return "Number of bodywork volumes: " + this.bodyWorkVolumesNumber
             + "\nCar color: " + this.color
             + "\nEngine type: " + this.engineType
             + "\nTire type: " + this.tireType
             + "\nStarter motor type: " + this.starterMotorType;
    }
}
Clique aqui para fazer o download do código completo de implementação deste Design Pattern.

Exemplo #2

Em um jogo lutadores de MMA (Mixed Martial Arts) brasileiros e japoneses utilizam diversos estilos de arte marcial (karatê, judô e jui-jitsu). Durante a luta eles podem mudar a arte utilizada nos golpes para ataque e defesa. O jogador atuando como técnico decide como configurar cada lutador de acordo com esses diferentes estilos de arte marcial. 
 
Fighter chama o método de execução (toAttack/defense) utilizando a interface MartialArt vinculada toda vez que precisa executar o algoritmo do golpe. Ele não sabe com que tipo de estratégia trabalha ou como o algoritmo é executado. Client cria um objeto de estratégia específico (karate, Judo, Jui-Jitsu) e o passa para o Fighter correspondente (BrazilianFighter, JapaneseFighter). Esse Fighter expôe um setter que permite que os clientes substituam a estratégia associada a ele em tempo de execução. 

Diagrama de Classe

Exemplo #2 - Diagrama

Participantes

  • Strategy (MartialArt): Define uma interface comum para todos os algoritmos apoiados.

  • ConcreteStrategy (Karate, Judo, Jui-Jitsu): Implementa os algoritmos usando a interface de Strategy.

  • Context (Fighter): É configurado com um objeto ConcreteStrategy e mantém uma referência para um objeto Strategy.

Código

/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public class Judo implements MartialArt {
    
    @Override
    public String toAttack() {
     return "Judo Ataque!";   
       
    }

    @Override
    public String toDefend() {
     return "Judo Defesa!";  
    }
    
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public class Karate implements MartialArt {
    
    @Override
    public String toAttack() {
     return "Karate Ataque!";   
       
    }
    
    @Override
    public String toDefend() {
     return "Karate Defesa!";  
    }
 
    
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public interface MartialArt {
    public String toAttack();
    public String toDefend();
    
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Main.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public class Client {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
            
        //Inicio da luta!!! 
        BrazilianFighter fighter1 = new BrazilianFighter();
        JapaneseFighter fighter2 = new JapaneseFighter();
                     
        Karate karat = new Karate();   
        Judo judo = new Judo();
        Jiujitsu jj = new Jiujitsu();
        
        fighter1.setMartialArt(karat);
        System.out.println(fighter1.toAttack());
        System.out.println(fighter1.toDefend());
        fighter1.setMartialArt(judo);
        System.out.println(fighter1.toAttack());
        System.out.println(fighter1.toDefend());
        
        fighter2.setMartialArt(judo);
        System.out.println(fighter2.toAttack());
        System.out.println(fighter2.toDefend());
        fighter2.setMartialArt(jj);
        System.out.println(fighter2.toAttack());
        System.out.println(fighter2.toDefend());
        
        //Fim da luta 
        
        // Inicio nova Luta!!
        
    }
    
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public abstract class Fighter {
    MartialArt martialArt;
        
    public void setMartialArt(MartialArt martialArt){
        this.martialArt = martialArt;
            
   }
    public abstract String toAttack();
        
    public abstract String toDefend();
           
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public class Jiujitsu  implements MartialArt {
  
    @Override
    public String toAttack() {
     return "Jiu-Jitsu Ataque!";   
       
    }

    @Override
    public String toDefend() {
     return "Jiu-Jitsu Defesa!";  
    }
    
    
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public class BrazilianFighter extends Fighter {

    public BrazilianFighter(){
        System.out.println("Lutador Brasileiro!");
    }
    @Override
    public String toAttack() {
       return martialArt.toAttack();
    }

    @Override
    public String toDefend() {
        return martialArt.toDefend();
    }
    
    
}
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package br.padroes.strategyFighter;

/**
 *
 * @author linus
 */
public class JapaneseFighter extends Fighter{
    
    public JapaneseFighter(){
         System.out.println("Lutador Japonês!");
    }
    
    @Override
    public String toAttack() {
       return martialArt.toAttack();
    }

    @Override
    public String toDefend() {
        return martialArt.toDefend();
    }
    
    
}
Clique aqui para fazer o download do código completo de implementação deste Design Pattern.

Padrões Relacionados

Este Padrão pode ser usado para resolver os seguintes problemas: