In this article, we will do an in-depth exploration of Command Design Pattern in Java. So, let’s get started.
What is Command Design Pattern in Java ?
Command Design Pattern in Java helps to decouple the invoker and the receiver.Four terms associated with the command pattern are command, receiver, invoker and client.
- Command is an interface with execute method. It is the core of contract.
- A client creates an instance of a command implementation and associates it with a receiver.
- An invoker instructs the command to perform an action.
- A Command implementation’s instance creates a binding between the receiver and an action.
- Receiver is the object that knows the actual steps to perform the action.
Example: Command Design Pattern in Java
We will take an example of an universal remote which can operate on electronic devices like AC,TV and Washing Machine.For simplicity, we will consider only two commands i.e., On and Off.
Class Diagram
Java Code
// ElectronicDevice Interface
package com.design.command;
public interface ElectronicDevice {
public void switchOn();
public void switchOff();
}
// TV Class
package com.design.command;
public class TV implements ElectronicDevice {
@Override
public void switchOn() {
System.out.println("TV switched On");
}
@Override
public void switchOff() {
System.out.println("TV switched Off");
}
}
// WashingMachine Class
package com.design.command;
public class WashingMachine implements ElectronicDevice {
@Override
public void switchOn() {
System.out.println("WashingMachine switched On");
}
@Override
public void switchOff() {
System.out.println("WashingMachine switched Off");
}
}
// AC Class
package com.design.command;
public class AC implements ElectronicDevice {
@Override
public void switchOn() {
System.out.println("AC switched On");
}
@Override
public void switchOff() {
System.out.println("AC switched Off");
}
}
// Command Interface
package com.design.command;
public interface Command {
public void execute();
}
// OnCommand Class
package com.design.command;
public class OnCommand implements Command {
private ElectronicDevice electronicDevice;
@Override
public void execute() {
electronicDevice.switchOn();
}
public OnCommand(ElectronicDevice electronicDevice) {
this.electronicDevice = electronicDevice;
}
}
// OffCommand Class
package com.design.command;
public class OffCommand implements Command {
private ElectronicDevice electronicDevice;
@Override
public void execute() {
electronicDevice.switchOff();
}
public OffCommand(ElectronicDevice electronicDevice) {
this.electronicDevice = electronicDevice;
}
}
// UniversalRemoteControl Class
package com.design.command;
public class UniversalRemoteControl {
private Command command;
public UniversalRemoteControl(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
public Command getCommand() {
return command;
}
public void setCommand(Command command) {
this.command = command;
}
}
// CommandDemo Class
package com.design.command;
public class CommandDemo {
public static void main(String[] args) {
ElectronicDevice tv = new TV();
//switch on TV
Command switchOnTv = new OnCommand(tv);
UniversalRemoteControl control = new UniversalRemoteControl(switchOnTv);
control.pressButton();
//switch off TV
Command switchOffTv = new OffCommand(tv);
control.setCommand(switchOffTv);
control.pressButton();
//switch on AC
ElectronicDevice ac = new AC();
Command switchOnAC = new OnCommand(ac);
control.setCommand(switchOnAC);
control.pressButton();
//switch off AC
Command switchOffAC = new OffCommand(ac);
control.setCommand(switchOffAC);
control.pressButton();
//switch on AC
ElectronicDevice washingMachine = new WashingMachine();
Command switchOnWM = new OnCommand(washingMachine);
control.setCommand(switchOnWM);
control.pressButton();
//switch off AC
Command switchOffWM = new OffCommand(washingMachine);
control.setCommand(switchOffWM);
control.pressButton();
}
}
// Output
TV switched On
TV switched Off
AC switched On
AC switched Off
WashingMachine switched On
WashingMachine switched Off
Use-Cases: Command Design Pattern in Java
- GUI Applications: Implementing GUI operations like buttons, menus, and keyboard shortcuts, where each action is encapsulated as a command.
- Undo/Redo Functionality: Enabling users to undo and redo operations by storing commands and their parameters.
- Remote Control Devices: Creating universal remote controls that execute various commands on different devices.
- Transaction Management: Handling database transactions as commands, allowing easy rollback and commit functionalities.
- Batch Processing: Orchestrating batch processing tasks with the ability to schedule, pause, resume, and cancel.
- Multi-Level Menus: Designing complex menus where each menu item is represented by a command.
Pros: Command Design Pattern in Java
- Decoupling: Separating sender and receiver of a command, reducing direct dependencies and promoting flexibility.
- Undo/Redo: Facilitating the implementation of undo and redo functionality with a history of executed commands.
- Flexibility: Easily adding new commands without modifying existing client code.
- Reusability: Commands can be reused across different contexts and scenarios.
- Complex Operations: Breaking down complex operations into smaller, manageable command objects.
- Logging and Auditing: Logging executed commands for auditing and debugging purposes.
Cons: Command Design Pattern in Java
- Increased Complexity: Introducing multiple command classes and their management might add complexity.
- Abstraction Overhead: Creating numerous command classes for simple tasks could result in abstraction overhead.
- Memory Usage: Storing command objects in memory could impact memory usage, especially in memory-intensive applications.
- Potential Overhead: Adding an additional layer of abstraction could lead to a slight performance overhead.
Best Practices: Command Design Pattern in Java
- Clear Command Interface: Define a clear interface for all command classes, typically with an
execute()
method. - Single Responsibility Principle: Ensure each command class has a single responsibility and encapsulates a specific action.
- Invoker Separation: Keep invoker and command objects separate to maintain clear responsibilities.
- Use Composite Pattern: Consider using the Composite pattern to group multiple commands into a composite command.
- Command Factory: Utilize a command factory to create instances of command objects with appropriate parameters.
- Testing: Thoroughly test command classes to ensure they perform the intended actions correctly.
- Command History: Implement a history mechanism to support undo and redo functionality if required.
- Documentation: Document each command class, its purpose, and its interaction with other classes.
- Use Enums or Constants: Use enums or constants to represent different types of commands for better readability.
- Avoid Over-Engineering: Use the Command pattern only when necessary, avoiding over-engineering for simple scenarios.
Conclusion: Command Design Pattern in Java
Command Design Pattern in Java provides a powerful way to decouple the sender and receiver of commands, promoting flexibility and reusability in various scenarios. By encapsulating operations as command objects, this pattern enables the implementation of undo/redo functionality, remote control devices, GUI interactions, and more. While offering benefits like improved code organization, reduced coupling, and complex task breakdown, it’s essential to consider potential downsides such as increased complexity and abstraction overhead. Adhering to best practices, like defining clear interfaces, separating responsibilities, and thoughtful testing, ensures the successful application of the Command pattern in Java. Remember to strike a balance between using the pattern to enhance code structure without over-engineering for simpler use cases.
Must Read Design Pattern Articles:
- Professional Tips: Top 10 Design Principles in Java 2023
- SOLID principles in Java: A Comprehensive Guide in 2023
- Design Patterns in Java: For Efficient Development 2023
Recommended Books:
- “Design Patterns: Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (also known as the Gang of Four book)
- “Head First Design Patterns” by Eric Freeman, Elisabeth Robson, Bert Bates, and Kathy Sierra