Conceito do Padrão de Estado
O padrão de estado é um design pattern comportamental que permite que um objeto modifique seu comportamento quando seu estado interno muda. Em vez de usar uma série de instruções condicionais para definir o comportamento, cada estado é encapsulado em uma clase separada, e o objeto delega as operações para o estado atual. Isso torna o código mais limpo e fácil de manter.
Estrutura do Padrão de Estado
A estrutura do padrão de estado envolve três componentes principais:
- Contexto (Context): Mantém uma referência ao objeto de estado atual e delega as solicitações para esse objeto.
- Estado (State): Define uma interface comum para todos os estados possíveis.
- Estado Concreto (ConcreteState): Implementa a interface de estado para um estado específico.
Exemplo em Java: Máquina de Venda Automática
Vamos implementar uma máquina de venda automática usando o padrão de estado. A máquina pode estar em diferentes estados: sem moeda, com moeda, vendendo e sem estoque.
Definição da Interface Estado
public interface Situacao {
void inserirMoeda();
void devolverMoeda();
void girarManivela();
void dispensarItem();
}
Implementação dos Estados Concretos
SemMoedaState
public class SemMoedaState implements Situacao {
private MaquinaDeVenda maquina;
public SemMoedaState(MaquinaDeVenda maquina) {
this.maquina = maquina;
}
public void inserirMoeda() {
System.out.println("Você inseriu uma moeda.");
maquina.setEstado(maquina.getComMoedaState());
}
public void devolverMoeda() {
System.out.println("Não há moeda para devolver.");
}
public void girarManivela() {
System.out.println("Insira uma moeda primeiro.");
}
public void dispensarItem() {
System.out.println("Por favor, insira uma moeda.");
}
}
ComMoedaState
public class ComMoedaState implements Situacao {
private MaquinaDeVenda maquina;
public ComMoedaState(MaquinaDeVenda maquina) {
this.maquina = maquina;
}
public void inserirMoeda() {
System.out.println("Já há uma moeda inserida.");
}
public void devolverMoeda() {
System.out.println("Moeda devolvida.");
maquina.setEstado(maquina.getSemMoedaState());
}
public void girarManivela() {
System.out.println("Você girou a manivela.");
maquina.setEstado(maquina.getVendendoState());
maquina.dispensarItem();
}
public void dispensarItem() {
System.out.println("Nenhum item disponível para dispensar.");
}
}
VendendoState
public class VendendoState implements Situacao {
private MaquinaDeVenda maquina;
public VendendoState(MaquinaDeVenda maquina) {
this.maquina = maquina;
}
public void inserirMoeda() {
System.out.println("Aguarde, já estamos processando sua compra.");
}
public void devolverMoeda() {
System.out.println("Não pode devolver a moeda, já girou a manivela.");
}
public void girarManivela() {
System.out.println("Girar duas vezes não resulta em dois itens.");
}
public void dispensarItem() {
maquina.liberarItem();
if (maquina.getQuantidade() > 0) {
maquina.setEstado(maquina.getSemMoedaState());
} else {
System.out.println("Ops, sem estoque!");
maquina.setEstado(maquina.getSemEstoqueState());
}
}
}
SemEstoqueState
public class SemEstoqueState implements Situacao {
private MaquinaDeVenda maquina;
public SemEstoqueState(MaquinaDeVenda maquina) {
this.maquina = maquina;
}
public void inserirMoeda() {
System.out.println("Não pode inserir moedas, a máquina está sem estoque.");
}
public void devolverMoeda() {
System.out.println("Não pode devolver moedas, nenhuma foi inserida.");
}
public void girarManivela() {
System.out.println("Girou a manivela, mas não há itens disponíveis.");
}
public void dispensarItem() {
System.out.println("Nenhum item disponível para dispensar.");
}
}
Classe Contexto
public class MaquinaDeVenda {
Situacao semMoedaState;
Situacao comMoedaState;
Situacao vendendoState;
Situacao semEstoqueState;
Situacao estadoAtual;
int quantidade = 0;
public MaquinaDeVenda(int quantidade) {
this.quantidade = quantidade;
semMoedaState = new SemMoedaState(this);
comMoedaState = new ComMoedaState(this);
vendendoState = new VendendoState(this);
semEstoqueState = new SemEstoqueState(this);
if (quantidade > 0) {
estadoAtual = semMoedaState;
} else {
estadoAtual = semEstoqueState;
}
}
public void inserirMoeda() {
estadoAtual.inserirMoeda();
}
public void devolverMoeda() {
estadoAtual.devolverMoeda();
}
public void girarManivela() {
estadoAtual.girarManivela();
estadoAtual.dispensarItem();
}
void setEstado(Situacao estado) {
estadoAtual = estado;
}
void liberarItem() {
System.out.println("Um item está sendo dispensado...");
if (quantidade > 0) {
quantidade--;
}
}
public Situacao getSemMoedaState() {
return semMoedaState;
}
public Situacao getComMoedaState() {
return comMoedaState;
}
public Situacao getVendendoState() {
return vendendoState;
}
public Situacao getSemEstoqueState() {
return semEstoqueState;
}
public int getQuantidade() {
return quantidade;
}
}
Teste da Máquina de Venda Automática
public class TesteMaquinaDeVenda {
public static void main(String[] args) {
MaquinaDeVenda maquina = new MaquinaDeVenda(5);
maquina.inserirMoeda();
maquina.girarManivela();
maquina.devolverMoeda();
maquina.inserirMoeda();
maquina.inserirMoeda();
maquina.girarManivela();
for (int i = 0; i < 6; i++) {
maquina.girarManivela();
}
}
}
Vantagens e Desvantagens
Vantagens
- Lógica Clara: Cada estado tem sua própria lógica, eliminando a necessidade de muitas estruturas condicionais.
- Extensibilidade: Novos estados podem ser adicionados facilmente sem modificar a clase de contexto.
- Mantenibilidade: Alterações em um estado não afetam outros estados.
Desvantagens
- Aumento de Classes: Cada estado requer uma nova classe, aumentando a complexidade.
- Complexidade de Transição: Gerenciar transições entre estados pode se tornar complicado.
Casos de Uso
- Sistemas de Workflow: Gestão de tarefas em diferentes estágios.
- Jogos: Controle de ações de personagens e cenários.
- Dispositivos Eletrônicoss: Gerenciamento de estados de dispositivos como impressoras e roteadores.