Command pattern
Command Pattern is one of the Behavioural Design Patterns.
The main key of this pattern is command interface
This command interface provides abstract “execute” method.
Each concrete command class provides different implementations of execute method.
Command pattern decouples the object which invokes the operation from the one which knows how to perform it.
In this pattern, request will be encapsulated as an object which makes clients to send different requests with different parameters
We also need to understand “Sender” and “Receiver” in this pattern
Request is sent to “Sender” and “sender” pass it to the encapsulated command object
Command object passes the request to the appropriate method of Receiver to perform the specific action
Steps to implement Command pattern
1) Create the receiver interface
2) Create implementation classes for Receiver interface
3) Create a command interface with execute method
4) Create implementation classes for command interface
5) Create command invoker class which calls execute method of command
6) Create a client program to test the pattern
Let’s perform these steps with an example
Consider an example of reading and writing to files of different format like excel,pdf etc
Let’s implement this requirement with below steps
1) Create receiver interface
- package com.kb.command;
- public interface FileReceiver {
- void readFile();
- void writeFile();
- }
package com.kb.command; public interface FileReceiver { void readFile(); void writeFile(); }
2) Create implementation classes for Receiver interface
We will have 2 different receivers , one for PDF and other one for excel
- package com.kb.command;
- public class PDFFileReceiver implements FileReceiver{
- @Override
- public void readFile() {
- System.out.println("PDF file read ... ");
- }
- @Override
- public void writeFile() {
- System.out.println("PDF file write ... ");
- }
- }
package com.kb.command; public class PDFFileReceiver implements FileReceiver{ @Override public void readFile() { System.out.println("PDF file read ... "); } @Override public void writeFile() { System.out.println("PDF file write ... "); } }
- package com.kb.command;
- public class ExcelFileReceiver implements FileReceiver{
- @Override
- public void readFile() {
- System.out.println("Excel file read ... ");
- }
- @Override
- public void writeFile() {
- System.out.println("Excel file write ... ");
- }
- }
package com.kb.command; public class ExcelFileReceiver implements FileReceiver{ @Override public void readFile() { System.out.println("Excel file read ... "); } @Override public void writeFile() { System.out.println("Excel file write ... "); } }
3) Create a command interface with execute method
- package com.kb.command;
- public interface Command {
- void execute();
- }
package com.kb.command; public interface Command { void execute(); }
4) Create implementation classes for command interface
We need to create 2 command classes one for Read operation and other one for write operation
- package com.kb.command;
- public class ReadFileCommand implements Command{
- FileReceiver fileReceiver;
- public ReadFileCommand(FileReceiver fileReceiver) {
- this.fileReceiver=fileReceiver;
- }
- @Override
- public void execute() {
- fileReceiver.readFile();
- }
- }
package com.kb.command; public class ReadFileCommand implements Command{ FileReceiver fileReceiver; public ReadFileCommand(FileReceiver fileReceiver) { this.fileReceiver=fileReceiver; } @Override public void execute() { fileReceiver.readFile(); } }
- package com.kb.command;
- public class WriteFileCommand implements Command{
- FileReceiver fileReceiver;
- public WriteFileCommand(FileReceiver fileReceiver) {
- this.fileReceiver=fileReceiver;
- }
- @Override
- public void execute() {
- fileReceiver.writeFile();
- }
- }
package com.kb.command; public class WriteFileCommand implements Command{ FileReceiver fileReceiver; public WriteFileCommand(FileReceiver fileReceiver) { this.fileReceiver=fileReceiver; } @Override public void execute() { fileReceiver.writeFile(); } }
5) Create command invoker class which calls execute method of command
- package com.kb.command;
- public class FileCommandInvoker {
- public Command command;
- public FileCommandInvoker(Command command){
- this.command=command;
- }
- public void execute(){
- this.command.execute();
- }
- }
package com.kb.command; public class FileCommandInvoker { public Command command; public FileCommandInvoker(Command command){ this.command=command; } public void execute(){ this.command.execute(); } }
6) Create a client program to test the pattern
- package com.kb.command;
- public class FileSystemClient {
- public static void main(String[] args) {
- // Creating receiver object
- FileReceiver pdfReceiver = new PDFFileReceiver();
- // creating command object and associate appropriate receiver
- Command readFileCommand = new ReadFileCommand(pdfReceiver);
- // Creating invoker and associating with Command
- FileCommandInvoker fileInvoker = new FileCommandInvoker(readFileCommand);
- // perform action on invoker object using execute method
- fileInvoker.execute();
- // creating command object and associate appropriate receiver
- Command writeFileCommand = new WriteFileCommand(pdfReceiver);
- // Creating invoker and associating with Command
- fileInvoker = new FileCommandInvoker(writeFileCommand);
- // perform action on invoker object using execute method
- fileInvoker.execute();
- }
- }
package com.kb.command; public class FileSystemClient { public static void main(String[] args) { // Creating receiver object FileReceiver pdfReceiver = new PDFFileReceiver(); // creating command object and associate appropriate receiver Command readFileCommand = new ReadFileCommand(pdfReceiver); // Creating invoker and associating with Command FileCommandInvoker fileInvoker = new FileCommandInvoker(readFileCommand); // perform action on invoker object using execute method fileInvoker.execute(); // creating command object and associate appropriate receiver Command writeFileCommand = new WriteFileCommand(pdfReceiver); // Creating invoker and associating with Command fileInvoker = new FileCommandInvoker(writeFileCommand); // perform action on invoker object using execute method fileInvoker.execute(); } }
Now we can see that both read and write commands got executed on PDFFileReceiver and hence the output is PDF file read and write operation
Similarly, If we pass ExcelFileReceiver to Commands then command will execure read and write operations of Excel file.
Important points about command pattern
Command is the main key of this pattern and we should have command interface with execute() method in it , this execute() method defines the actual contract for all the concrete commands
Receiver and command implementations kept isolated and command uses the receiver
Command implementation chooses the right receiver based on the request
We will have invoker class to pass the request from client to command
Client has to associate appropriate command to invoker and associate appropriate receiver to command
Command design pattern is easily extendible, we can add new action methods in receivers and create new Command implementations without changing the client code.
The drawback with Command design pattern is that the code gets huge and confusing with high number of action methods and because of so many associations