Description / Meta Description
Learn the Command Design Pattern in Java with practical examples. Understand how Command encapsulates requests as objects, enables undo operations, task scheduling, workflow execution, and decouples request senders from receivers. Discover real-world examples from Spring Batch, Quartz Scheduler, workflow engines, and enterprise applications.
Command Design Pattern in Java: Encapsulating Requests as Objects
In the previous article, we explored the Observer Pattern, which enables event-driven communication through publishers and subscribers.
Observer answers:
How do I notify multiple interested parties when something happens?
Command answers a different question:
How do I represent an action or request as an object?
This pattern sits at the heart of:
- Job Schedulers
- Spring Batch
- Quartz Scheduler
- Workflow Engines
- Undo/Redo Systems
- Task Queues
- Enterprise Integration Platforms
If you’ve ever:
- Submitted a task for later execution
- Scheduled a batch job
- Built an approval workflow
- Implemented undo functionality
you’ve likely encountered Command Pattern.
The Problem: Tight Coupling Between Sender and Receiver
Imagine a UI button.
When clicked:
Button Click
↓
Generate Report
A naive implementation:
public class ReportButton {
private ReportService service =
new ReportService();
public void click() {
service.generateReport();
}
}
Looks fine.
Now requirements evolve.
The button may perform:
Generate Report
Export PDF
Send Email
Create Invoice
Run Batch Job
Suddenly:
Button
Knows Too Much
The sender becomes tightly coupled to the receiver.
This violates good design principles.
What We Really Want
Instead of:
Button
│
▼
Specific Service
We want:
Button
│
▼
Command
│
▼
Receiver
The button shouldn’t care what happens.
It should simply execute a command.
This is Command Pattern.
What is Command Pattern?
Command is a Behavioral Design Pattern that:
Encapsulates a request as an object, allowing requests to be parameterized, queued, logged, scheduled, or undone.
Think of a restaurant.
Customer:
Place Order
Waiter:
Takes Order
Kitchen:
Prepares Food
The waiter doesn’t cook.
The kitchen doesn’t interact directly with the customer.
The order acts as the command.
Real Life Analogy
Imagine a TV remote.
Remote button:
Power On
The remote doesn’t know:
How TV boots
How circuits work
How hardware initializes
It simply sends a command.
The television executes it.
Classic Command Pattern.
Command Architecture
Client
│
▼
Command
│
▼
Receiver
▲
│
Invoker
Components:
Client
Creates Command
Invoker
Executes Command
Receiver
Performs Work
Step 1: Create Command Interface
public interface Command {
void execute();
}
Simple.
Every command supports execution.
Step 2: Create Receiver
public class ReportService {
public void generateReport() {
System.out.println(
"Generating Report");
}
}
Receiver contains actual business logic.
Step 3: Create Concrete Command
public class GenerateReportCommand
implements Command {
private ReportService service;
public GenerateReportCommand(
ReportService service) {
this.service = service;
}
@Override
public void execute() {
service.generateReport();
}
}
Notice:
Command delegates to receiver.
Step 4: Create Invoker
public class Button {
private Command command;
public Button(Command command) {
this.command = command;
}
public void click() {
command.execute();
}
}
Button knows only:
Command
Not ReportService.
Step 5: Client Usage
ReportService service =
new ReportService();
Command command =
new GenerateReportCommand(
service);
Button button =
new Button(command);
button.click();
Output:
Generating Report
The button never knows what work is actually performed.
Why Command Works
Without Command:
Button
│
▼
Report Service
Strong coupling.
With Command:
Button
│
▼
Command
│
▼
Service
Loose coupling.
Flexible execution.
Enterprise Example: Job Scheduling
Suppose a scheduler must execute:
Daily Report
Monthly Billing
User Cleanup
Inventory Sync
Without Command:
if(jobType.equals(...))
Large conditional blocks emerge.
With Command:
DailyReportCommand
BillingCommand
CleanupCommand
InventorySyncCommand
Scheduler executes:
command.execute();
regardless of job type.
Quartz Scheduler Example
Quartz internally works very similarly.
Developer creates:
public class BillingJob
implements Job {
public void execute(
JobExecutionContext ctx) {
}
}
Quartz stores:
Job Definition
and executes later.
Conceptually:
Job
=
Command
Spring Batch Example
Batch jobs contain:
Read
Process
Write
Each step behaves similarly to a command.
Framework executes tasks without knowing implementation details.
Undo Functionality
One of the classic uses of Command.
Example:
Copy
Paste
Delete
Rename
Each action becomes a command.
execute()
undo()
can be implemented.
Example:
public interface Command {
void execute();
void undo();
}
Now:
Execute
Undo
Redo
become possible.
Workflow Engine Example
Approval system:
Approve Loan
Reject Loan
Escalate Loan
Each action becomes a command.
Workflow engine simply executes:
command.execute();
without knowing implementation details.
Queue-Based Processing
Commands work beautifully with queues.
Architecture:
Producer
│
▼
Queue
│
▼
Worker
Queue stores commands.
Workers execute commands later.
This enables:
Asynchronous Processing
Retry
Scheduling
Persistence
Spring Framework Example
Many Spring features resemble Command Pattern.
Examples:
TaskExecutor
Runnable
Callable
Batch Jobs
Scheduled Tasks
Each encapsulates work as an object.
Benefits of Command Pattern
1. Loose Coupling
Invoker and receiver remain independent.
2. Queuing
Commands can be stored and executed later.
3. Scheduling
Commands work naturally with schedulers.
4. Undo/Redo Support
Classic advantage.
5. Logging and Auditing
Commands can be recorded and replayed.
6. Workflow Support
Complex processes become manageable.
Common Mistakes
Mistake 1: Command Explosion
Creating hundreds of tiny commands unnecessarily.
Use where behavior is truly independent.
Mistake 2: Business Logic in Invoker
Invoker should execute commands.
Not contain business workflows.
Mistake 3: Forgetting Receiver Separation
Command should delegate work.
Receiver should perform work.
Keep responsibilities separate.
Command vs Strategy
Common interview question.
Strategy
Represents:
Algorithm Choice
Example:
Card Payment
UPI Payment
Wallet Payment
Command
Represents:
Action
Task
Request
Example:
Generate Report
Delete User
Create Invoice
Command vs Observer
Observer
One Event
Many Listeners
Command
One Request
One Execution
Different intent.
Command vs Chain of Responsibility
Command
Encapsulates action.
Execute Task
Chain of Responsibility
Processes request through:
Handler 1
Handler 2
Handler 3
Pipeline behavior.
When Should You Use Command?
Use Command when:
✔ Requests must be encapsulated
✔ Scheduling is required
✔ Queuing is required
✔ Undo functionality exists
✔ Workflow execution exists
✔ Task execution varies
Examples:
- Quartz Jobs
- Spring Batch
- Workflow Engines
- Approval Systems
- Task Queues
- Scheduler Frameworks
Avoid Command when:
❌ Direct method invocation is sufficient
❌ Additional abstraction adds no value
❌ Simple systems don’t need scheduling or queuing
Behavioral Patterns Covered So Far
| Pattern | Purpose |
|---|---|
| Strategy | Choose algorithms dynamically |
| Observer | Publish-subscribe communication |
| Command | Encapsulate actions as objects |
Behavioral Pattern Cheat Sheet
Strategy
→ Choose Behavior
Observer
→ Broadcast Events
Command
→ Encapsulate Actions
Final Thoughts
The Command Pattern solves a common enterprise challenge:
How do we represent actions, tasks, and requests as first-class objects?
By encapsulating requests into command objects, we gain:
- Flexibility
- Scheduling
- Queuing
- Undo Support
- Workflow Execution
- Better Decoupling
This is why Command appears throughout:
- Spring Batch
- Quartz Scheduler
- Workflow Engines
- Task Queues
- Enterprise Platforms
Whenever you find yourself needing to store, schedule, queue, retry, audit, or undo actions, Command Pattern is often the right choice.
In the next article, we’ll explore another extremely important Behavioral Pattern:
Chain of Responsibility Pattern — Building Request Processing Pipelines
You’ll learn why Spring Security Filters, Servlet Filters, Validation Chains, Middleware Frameworks, and API Gateways heavily rely on Chain of Responsibility concepts.