Implementação do Padrão de Projeto Strategy em Java

No paradigma da programação orientada a objetos, a herança é frequentemente utilizada para reaproveitar código comum em uma superclasse. Contudo, quando o número de subclasses aumenta e os comportamentos começam a divergir significativamente, a simples herança pode levar a um excesso de sobrescritas (overriding), dificultando a manutenção e violando princípios de design como o Open/Closed Principle.

O padrão Strategy resolve esse problema ao definir uma família de algoritmos, encapsulando cada um deles e tornando-os intercambiáveis. Isso permite que o comportamento de um objeto mude dinamicamente através da composição, em vez de depender estritamente da herança.

O Problema da Herança Rígida

Considere um cenário onde temos uma classe base para animais. Inicialmente, definimos um método genérico para alimentação. À medida que adicionamos animais específicos, somos forçados a soberscrever esse método repetidamente.


// Abordagem problemática com herança pura
public class Animal {
    public void executarAlimentacao() {
        System.out.println("O animal está comendo.");
    }
}

class Leao extends Animal {
    @Override
    public void executarAlimentacao() {
        System.out.println("Leão comendo carne.");
    }
}

class Zebra extends Animal {
    @Override
    public void executarAlimentacao() {
        System.out.println("Zebra comendo ervas.");
    }
}

Refatoração com o Padrão Strategy

Para tornar o sistema flexível, extraímos o comportamento de alimentação para uma interface e criamos implementações concretas para cada tipo de dieta. A classe principal passa a utilizar a composição para delegar a execução desse comportamento.


// 1. Definição da Interface de Estratégia
interface DietaStrategy {
    void comer();
}

// 2. Implementações Concretas das Estratégias
class DietaCarnivora implements DietaStrategy {
    private String especie;

    public DietaCarnivora(String especie) {
        this.especie = especie;
    }

    @Override
    public void comer() {
        System.out.println(especie + " está caçando e comendo carne.");
    }
}

class DietaHerbivora implements DietaStrategy {
    private String especie;

    public DietaHerbivora(String especie) {
        this.especie = especie;
    }

    @Override
    public void comer() {
        System.out.println(especie + " está pastando e comendo vegetação.");
    }
}

// 3. Classe de Contexto utilizando Composição
public abstract class Animal {
    protected DietaStrategy dietaStrategy;

    public void setDieta(DietaStrategy dietaStrategy) {
        this.dietaStrategy = dietaStrategy;
    }

    public void realizarAlimentacao() {
        if (dietaStrategy != null) {
            dietaStrategy.comer();
        } else {
            System.out.println("Comportamento de dieta não definido.");
        }
    }
}

// Subclasses simplificadas
class Leao extends Animal {
    public Leao() {
        // Pode ser definido um padrão ou injetado externamente
    }
}

class Girafa extends Animal {
    public Girafa() {
    }
}

// 4. Demonstração de Uso
public class SistemaZoologico {
    public static void main(String[] args) {
        Animal leao = new Leao();
        leao.setDieta(new DietaCarnivora("Leão Africano"));
        leao.realizarAlimentacao();

        Animal girafa = new Girafa();
        girafa.setDieta(new DietaHerbivora("Girafa Reticulada"));
        girafa.realizarAlimentacao();
        
        // Mudança dinâmica de comportamento
        System.out.println("--- Alteração dinâmica ---");
        leao.setDieta(new DietaHerbivora("Leão em dieta especial"));
        leao.realizarAlimentacao();
    }
}

Ao adotar essa estrutura, ganhamos a flexibilidade de adicionar novos tipos de alimentação sem modificar as classes de animais existentes. Além disso, diferentes animais podem compartilhar a mesma instância de estratégia ou trocar de comportamento em tempo de execução, promovendo um baixo acoplamanto entre a lógica de negócio e as entidades de dados.

Tags: java design patterns Strategy Pattern OOP Software Architecture

Publicado em 6-18 10:01