Description / Meta Description
Learn the State Design Pattern in Java with practical examples. Understand how State eliminates complex state-based if-else logic, enables clean state transitions, and powers workflow engines, order management systems, approval processes, ticketing systems, and enterprise applications.
State Design Pattern in Java: Changing Object Behavior Dynamically Based on Its Current State
In the previous article, we explored the Chain of Responsibility Pattern, which helps process requests through a pipeline of independent handlers.
Chain of Responsibility answers:
How do I process a request through multiple stages?
State answers a different question:
How do I change an object’s behavior when its internal state changes?
This pattern is extremely common in enterprise software.
If you’ve worked with:
- Order Management Systems
- Approval Workflows
- Ticketing Platforms
- Workflow Engines
- Banking Applications
- Finite State Machines
then you’ve likely encountered State Pattern.
The Problem: State-Based if-else Explosion
Imagine an e-commerce order.
An order can be:
NEW
PAID
SHIPPED
DELIVERED
CANCELLED
Different actions are allowed in different states.
For example:
NEW
→ Pay
→ Cancel
PAID
→ Ship
→ Refund
SHIPPED
→ Deliver
DELIVERED
→ Review
CANCELLED
→ No Actions
A naive implementation usually becomes:
public class Order {
private String state;
public void process() {
if(state.equals("NEW")) {
// payment logic
} else if(state.equals("PAID")) {
// shipping logic
} else if(state.equals("SHIPPED")) {
// delivery logic
} else if(state.equals("DELIVERED")) {
// review logic
}
}
}
Looks manageable initially.
Then business requirements evolve:
PARTIALLY_PAID
RETURN_REQUESTED
RETURNED
REFUNDED
ON_HOLD
Now:
if
else if
else if
else if
else if
else if
else if
The class becomes difficult to maintain.
Every new state requires modifying existing code.
This violates:
Open/Closed Principle
What We Really Want
Instead of:
Order
│
└── Huge State Logic
We want:
Order
│
▼
Current State
│
├── New State
├── Paid State
├── Shipped State
└── Delivered State
Each state owns its behavior.
The order simply delegates.
This is State Pattern.
What is State Pattern?
State is a Behavioral Design Pattern that:
Allows an object to alter its behavior when its internal state changes.
In simple terms:
Same Object
Different Behavior
Based On Current State
The object appears to change its class.
Real Life Analogy
Consider a traffic signal.
Current state:
GREEN
Behavior:
Vehicles Move
Change state:
RED
Behavior:
Vehicles Stop
The traffic signal remains the same object.
Only its state changes.
Its behavior changes automatically.
State Architecture
Context
│
▼
State Interface
▲
│
New State
Paid State
Shipped State
Delivered State
Context delegates behavior to the current state.
Step 1: Create State Interface
public interface OrderState {
void processOrder(
OrderContext context);
}
Every state must implement behavior.
Step 2: Create Context
public class OrderContext {
private OrderState state;
public OrderContext(
OrderState state) {
this.state = state;
}
public void setState(
OrderState state) {
this.state = state;
}
public void process() {
state.processOrder(this);
}
}
Context stores the current state.
Step 3: Create New State
public class NewState
implements OrderState {
@Override
public void processOrder(
OrderContext context) {
System.out.println(
"Processing Payment");
context.setState(
new PaidState());
}
}
Notice:
State Transition
happens inside the state itself.
Step 4: Create Paid State
public class PaidState
implements OrderState {
@Override
public void processOrder(
OrderContext context) {
System.out.println(
"Shipping Order");
context.setState(
new ShippedState());
}
}
Step 5: Create Shipped State
public class ShippedState
implements OrderState {
@Override
public void processOrder(
OrderContext context) {
System.out.println(
"Delivering Order");
context.setState(
new DeliveredState());
}
}
Step 6: Create Delivered State
public class DeliveredState
implements OrderState {
@Override
public void processOrder(
OrderContext context) {
System.out.println(
"Order Complete");
}
}
Client Usage
OrderContext order =
new OrderContext(
new NewState());
order.process();
order.process();
order.process();
order.process();
Output:
Processing Payment
Shipping Order
Delivering Order
Order Complete
Same object.
Different behavior.
Different state.
Why State Works
Without State:
Order
│
├── if NEW
├── if PAID
├── if SHIPPED
├── if DELIVERED
└── if CANCELLED
Huge conditionals.
With State:
Order
│
▼
Current State
│
▼
State Object
Behavior remains isolated.
Order Lifecycle Visualization
NEW
│
▼
PAID
│
▼
SHIPPED
│
▼
DELIVERED
Each node becomes a separate state class.
Enterprise Example: Loan Approval Workflow
Loan application states:
SUBMITTED
│
▼
UNDER_REVIEW
│
▼
APPROVED
│
▼
DISBURSED
Different actions allowed at each stage.
State Pattern models this naturally.
Ticketing System Example
Support ticket:
OPEN
│
▼
IN_PROGRESS
│
▼
RESOLVED
│
▼
CLOSED
Behavior changes automatically.
For example:
CLOSED Ticket
Cannot Be Assigned
Cannot Be Edited
State controls behavior.
ATM Machine Example
Classic GoF example.
States:
NO_CARD
CARD_INSERTED
PIN_VERIFIED
TRANSACTION_IN_PROGRESS
Each state supports different operations.
Example:
NO_CARD
Insert Card
✓
Withdraw Cash
✗
State Pattern makes this easy.
Spring State Machine
Spring provides:
spring-statemachine
for implementing workflow systems.
Example:
ORDER_CREATED
ORDER_PAID
ORDER_SHIPPED
ORDER_DELIVERED
Exactly State Pattern at enterprise scale.
State vs Strategy
Most common interview question.
The structures look similar.
Strategy
Purpose:
Choose Behavior
Client chooses algorithm.
Example:
UPI Payment
Card Payment
Wallet Payment
State
Purpose:
Behavior Changes Automatically
Based on current state.
Example:
NEW
PAID
SHIPPED
State transitions itself.
Visual Difference
Strategy:
Client
│
▼
Choose Strategy
State:
Current State
│
▼
Changes To
Next State
Automatically.
State vs Chain of Responsibility
Chain
Request flows through:
Handler 1
Handler 2
Handler 3
State
Object changes behavior:
State 1
↓
State 2
↓
State 3
Different concepts.
Benefits of State Pattern
1. Eliminates Large if-else Blocks
Primary benefit.
2. Open/Closed Principle
Add new states easily.
3. Cleaner Code
State-specific logic remains isolated.
4. Easier Testing
Each state can be tested independently.
5. Natural Workflow Modeling
Perfect for business processes.
Common Mistakes
Mistake 1: Too Many States
If only:
2 States
exist, State Pattern may be overkill.
Mistake 2: Transition Logic Everywhere
Keep transitions inside states.
Avoid scattering transition rules.
Mistake 3: Confusing State With Status Fields
Simply having:
String status;
is not State Pattern.
State Pattern delegates behavior to state objects.
When Should You Use State Pattern?
Use State when:
✔ Behavior changes based on status
✔ Large state-based conditionals exist
✔ Workflow systems exist
✔ State transitions are important
✔ Business processes have lifecycles
Examples:
- Order Processing
- Ticket Management
- Approval Systems
- Banking Workflows
- ATM Machines
- Workflow Engines
Avoid State when:
❌ Only one or two states exist
❌ Behavior never changes
❌ Simpler conditionals are sufficient
Behavioral Patterns Covered So Far
| Pattern | Purpose |
|---|---|
| Strategy | Choose algorithms dynamically |
| Observer | Publish-subscribe communication |
| Command | Encapsulate actions |
| Chain of Responsibility | Process requests through handlers |
| State | Change behavior based on state |
Behavioral Pattern Cheat Sheet
Strategy
→ Choose Behavior
Observer
→ Broadcast Events
Command
→ Encapsulate Actions
Chain of Responsibility
→ Process Through Pipeline
State
→ Change Behavior Based On State
Final Thoughts
The State Pattern solves a common enterprise challenge:
How do we manage complex workflows and state transitions without filling our codebase with endless conditional logic?
By moving behavior into dedicated state objects, we gain:
- Better maintainability
- Cleaner workflows
- Easier testing
- Flexible state transitions
- Improved scalability
This is why State Pattern powers:
- Order Management Systems
- Workflow Engines
- Ticketing Platforms
- Banking Applications
- Approval Systems
- Spring State Machine
Whenever you encounter an object whose behavior depends heavily on its current status, State Pattern is often the ideal solution.
In the next article, we’ll explore:
Template Method Design Pattern — Defining the Skeleton of an Algorithm While Allowing Subclasses to Customize Individual Steps
You’ll learn how frameworks, batch processing systems, Spring components, and enterprise workflows use Template Method to standardize processes while preserving flexibility.