Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
155: The Command Pattern
You've likely reached a point in your project where you have a class that's starting to look like a "God Object"—a piece of code that knows too much and does too much. Usually, this happens when you're tying your user interface (like a button or a menu) directly to the business logic. That's where the Command Pattern comes in. It's basically a way to turn a request into a stand-alone object.
Why can't I just call the method directly on the object?
Sure, you could. If your Button class calls light.turnOn() directly, it works. But now your Button is hard-wired to the Light class. What happens when you want that same button to open the garage door? Or what if you want to group three different actions—turn off the lights, lock the doors, and arm the alarm—into one "Leave House" button?
By using the Command Pattern, the Button doesn't know what it's actually doing. It just knows it has a Command object and it needs to call execute() on it. I've seen this save countless hours of refactoring in large-scale systems because it completely decouples the object that triggers the action from the object that actually performs the logic.
How do I actually structure this in Java?
You need four things: a Command interface, a Concrete Command, a Receiver (the thing actually doing the work), and an Invoker (the thing triggering the command). Let's look at a smart home example.
// The Command Interface
interface Command {
void execute();
void undo();
}
// The Receiver: This is where the actual logic lives
class Light {
public void on() { System.out.println("Light is ON"); }
public void off() { System.out.println("Light is OFF"); }
}
// Concrete Command: It wraps the receiver
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
public void undo() {
light.off();
}
}
// The Invoker: It doesn't know what the command does, just how to trigger it
class RemoteControl {
private Command slot;
public void setCommand(Command command) {
this.slot = command;
}
public void pressButton() {
slot.execute();
}
}
Notice that the RemoteControl doesn't have a single reference to the Light class. It only knows about the Command interface. This is the "magic" of the pattern.
Is this how "Undo" functionality is actually built?
Exactly. This is the most common real-world use case for the Command Pattern. If you just call methods directly, you have to manually track the previous state of every single object to reverse an action. That's a nightmare.
With the Command Pattern, the ConcreteCommand object stores the state needed to reverse the action. In the example above, LightOnCommand knows that the opposite of on() is off(). If you're building a text editor, a PasteCommand would store the text that was overwritten so it can put it back during undo().
To make this professional, I usually recommend keeping a Stack<Command> in your Invoker. Every time you call execute(), you push that command onto the stack. When the user hits Ctrl+Z, you pop the last command and call its undo() method. It's clean, predictable, and easy to test.
📋 Practical Task
Exercise: Implementing a Macro-Enabled Smart Home Controller
You are building a home automation system. You already have the Command interface and Light / Fan receiver classes. Your goal is to implement a MacroCommand.
A MacroCommand is a command that contains a List<Command>. When its execute() method is called, it should loop through all the commands in its list and execute them in order. This allows the user to trigger multiple actions (e.g., "Movie Mode": dim lights, turn on projector, close blinds) with a single button press.
Requirements:
- Create a class
MacroCommandthat implements theCommandinterface. - Add a constructor that accepts a
List<Command>. - Implement
execute()to trigger all commands in the list. - Implement
undo()to trigger the undo operations of the commands in the list in reverse order (this is crucial for maintaining system state). - In your
mainmethod, create a "Party Mode" macro that turns on multiple lights and a music system, then execute it and undo it.
There are no comments for now.