Padrão State
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 74 de 87.
O State Pattern é um padrão de projeto comportamental que permite que um objeto altere seu comportamento quando seu estado interno muda. O objeto parece mudar sua classe, mas, na realidade, ele delega o comportamento para diferentes objetos de estado. Pense em uma máquina de venda automática: sua resposta ao pressionar um botão depende se ela está ociosa, se tem dinheiro inserido ou se está dispensando um produto.
Em vez de usar instruções condicionais complexas para lidar com diferentes estados, você encapsula cada estado em sua própria classe. O padrão envolve um Context que mantém uma referência ao estado atual, e classes State que definem o comportamento para cada estado:
interface State {
void handle(Context context);
}
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}Cada estado concreto implementa o comportamento e pode disparar transições para outros estados:
class IdleState implements State {
public void handle(Context context) {
System.out.println("Idle: Insert coin to start");
context.setState(new ActiveState());
}
}
class ActiveState implements State {
public void handle(Context context) {
System.out.println("Active: Processing...");
context.setState(new IdleState());
}
}O contexto delega solicitações ao seu estado atual, e o comportamento muda automaticamente conforme o estado muda:
Context context = new Context();
context.setState(new IdleState());
context.request(); // Inativo: Insira a moeda para começar
context.request(); // Ativo: Processando...O Padrão State é ideal quando o comportamento de um objeto depende fortemente de seu estado e deve mudar em tempo de execução. Ele elimina grandes blocos condicionais e torna a adição de novos estados direta — basta criar uma nova classe que implemente a interface State.
Desafio
FácilVamos construir um sistema de fluxo de trabalho de documentos usando o State Pattern! Você criará um sistema que modela como um documento se move através de diferentes estágios—Draft, Review e Published—com cada estado determinando quais ações estão disponíveis e como o documento se comporta quando você tenta editá-lo ou aprová-lo.
Você organizará seu código em quatro arquivos:
DocumentState.java: Defina a interfaceDocumentStateque todos os estados implementarão. Ela deve declarar dois métodos:edit(Document doc)para tentar editar o documento, eapprove(Document doc)para tentar aprovar/avançar o documento para o próximo estágio.States.java: Crie três classes de estado concretas que implementamDocumentState:DraftState- Quandoeditfor chamado, imprimaEditing draft.... Quandoapprovefor chamado, imprimaDraft approved. Moving to review.e mude o estado do documento paraReviewState.ReviewState- Quandoeditfor chamado, imprimaCannot edit during review.(sem mudança de estado). Quandoapprovefor chamado, imprimaReview complete. Publishing document.e mude paraPublishedState.PublishedState- Quandoeditfor chamado, imprimaCannot edit published document.. Quandoapprovefor chamado, imprimaDocument already published.. Nenhuma das ações altera o estado.Document.java: Crie a classe de contexto que mantém o estado atual. SeuDocumentdeve ter:Um campo privado que contém o
DocumentStateatual, inicializado comoDraftStateno construtor.Um método
setState(DocumentState state)que altera o estado atual.Um método
edit()que delega para o métodoeditdo estado atual.Um método
approve()que delega para o métodoapprovedo estado atual.Um método
getStatus()que retorna o nome simples da classe do estado atual (usegetClass().getSimpleName()).Main.java: Demonstre seu sistema de estados! Você receberá uma entrada: uma sequência de ações como uma string separada por vírgulas, onde cada ação éeditouapprove(por exemplo:edit,approve,edit,approve).Crie um
Documente imprima seu status inicial no formatoStatus: [state]. Em seguida, processe cada ação em ordem, chamando o método apropriado no documento. Após cada ação, imprima o status atual.
Você receberá uma entrada: uma string de ações separada por vírgulas.
Por exemplo, com a entrada edit,approve,approve, sua saída seria:
Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedStateObserve como a mesma chamada approve() produz resultados diferentes dependendo do estado atual do documento—esta é a essência do State Pattern! O documento não usa condicionais para verificar seu estado; em vez disso, ele delega o comportamento ao objeto de estado atual, que lida com a ação apropriadamente e aciona transições quando necessário.
Folha de consulta
O State Pattern é um padrão de projeto comportamental que permite que um objeto altere seu comportamento quando seu estado interno muda, delegando o comportamento para diferentes objetos de estado em vez de usar instruções condicionais complexas.
O padrão consiste em um Context que mantém uma referência ao estado atual, e classes State que definem o comportamento para cada estado:
interface State {
void handle(Context context);
}
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}Cada estado concreto implementa o comportamento e pode disparar transições para outros estados:
class IdleState implements State {
public void handle(Context context) {
System.out.println("Idle: Insert coin to start");
context.setState(new ActiveState());
}
}
class ActiveState implements State {
public void handle(Context context) {
System.out.println("Active: Processing...");
context.setState(new IdleState());
}
}O contexto delega as solicitações ao seu estado atual, e o comportamento muda automaticamente conforme o estado se altera:
Context context = new Context();
context.setState(new IdleState());
context.request(); // Idle: Insert coin to start
context.request(); // Active: Processing...O State Pattern é ideal quando o comportamento de um objeto depende fortemente de seu estado e deve mudar em tempo de execução. Ele elimina grandes blocos condicionais e torna a adição de novos estados algo simples.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Criar um novo Document
// TODO: Imprimir o status inicial no formato "Status: [state]"
// TODO: Dividir a entrada por vírgula para obter as ações individuais
// TODO: Percorrer cada ação
// - Se a ação for "edit", chamar edit() no document
// - Se a ação for "approve", chamar approve() no document
// - Após cada ação, imprimir o status atual
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator