State
O State é um padrão comportamental utilizado quando um objeto pode assumir diferentes estados e seu comportamento muda de acordo com o estado atual.
Em vez de criar vários if ou switch:
if (state === "pending") {
// ...
} else if (state === "approved") {
// ...
} else if (state === "cancelled") {
// ...
}
podemos encapsular o comportamento de cada estado em uma classe própria.
A ideia principal é:
Permitir que um objeto altere seu comportamento quando seu estado interno muda.
O problema
Imagine um pedido:
PENDING
↓
APPROVED
↓
SHIPPED
↓
DELIVERED
Cada estado permite determinadas operações.
Por exemplo:
- Um pedido
PENDINGpode ser aprovado. - Um pedido
APPROVEDpode ser enviado. - Um pedido
SHIPPEDpode ser entregue.
Uma implementação simples poderia ser:
class Order {
state = "pending";
process() {
if (this.state === "pending") {
this.state = "approved";
} else if (
this.state === "approved"
) {
this.state = "shipped";
} else if (
this.state === "shipped"
) {
this.state = "delivered";
}
}
}
Conforme o sistema cresce, esses if começam a ficar difíceis de manter.
Implementando State
Criamos uma interface:
interface OrderState {
process(order: Order): void;
}
Estado inicial:
class PendingState
implements OrderState {
process(order: Order) {
console.log(
"Pedido aprovado"
);
order.setState(
new ApprovedState()
);
}
}
Estado aprovado:
class ApprovedState
implements OrderState {
process(order: Order) {
console.log(
"Pedido enviado"
);
order.setState(
new ShippedState()
);
}
}
Estado enviado:
class ShippedState
implements OrderState {
process(order: Order) {
console.log(
"Pedido entregue"
);
order.setState(
new DeliveredState()
);
}
}
Estado final:
class DeliveredState
implements OrderState {
process(order: Order) {
console.log(
"Pedido já foi entregue"
);
}
}
Agora temos o contexto:
class Order {
private state:
OrderState =
new PendingState();
setState(
state: OrderState
) {
this.state = state;
}
process() {
this.state.process(
this
);
}
}
Podemos utilizar:
const order =
new Order();
order.process();
// Pedido aprovado
order.process();
// Pedido enviado
order.process();
// Pedido entregue
order.process();
// Pedido já foi entregue
O objeto muda seu comportamento conforme o estado.
Exemplo prático: conexão
Outro exemplo seria uma conexão de rede:
Disconnected
↓
Connecting
↓
Connected
↓
Disconnected
Cada estado possui comportamentos diferentes.
Por exemplo:
interface ConnectionState {
connect(): void;
disconnect(): void;
}
Uma conexão Disconnected pode iniciar uma conexão.
Uma conexão Connected pode enviar dados.
Uma conexão Connecting pode aguardar o resultado.
Cada estado encapsula suas próprias regras.
Quando usar?
State é útil quando:
- Um objeto possui vários estados.
- O comportamento muda dependendo do estado.
- Existem muitos
ifouswitchrelacionados ao estado. - As regras de transição estão ficando complexas.
Exemplos:
Pedidos
Máquinas de estado
Conexões
Jogos
Fluxos de autenticação
Processos de pagamento
Workflows
A ideia principal é:
Transformar cada estado em um objeto que sabe como se comportar e como mudar para o próximo estado.