Encapsulating Invocation With the Command Design Pattern
Join the DZone community and get the full member experience.Join For Free
The Command Design Pattern takes encapsulation, one of the key pillars of Object-Oriented Programming to a whole new level. So far, we have seen encapsulation as a way to bind data and methods in a single entity called class. Encapsulation has more to offer and with the help of the Command Design Pattern, we can do much more. We can encapsulate method invocation by following what the command design pattern has to offer.
Yes, you read that right! Why would we ever do that? There are a lot of things in the world of computer science that cannot be achieved efficiently without trade-offs. Have you ever wondered how operating systems are able to execute a hell lot of operations without even caring what kind of operations have queued up in the job queue? How does it know that it needs to make a network request at one time and open up a video player at another time? The guess is easy, it has something to do with invocating methods by encapsulating them. We will see a code example in the article and that should help you realize the essence of it.
What Is the Command Design Pattern?
The command design pattern is a behavioral design pattern in which an object is used to encapsulate information needed to perform an action. Behavioral design patterns deal with how the objects communicate with each other.
The command design pattern decouples one object from the other and that is how method invocation is encapsulated (you will see this in a bit). There are a few key terms that we need to get a hold of to better understand the pattern.
Let us see what those are: (If these do not make sense right now, with the help of code example, you will get the idea).
- Client – In order to create a command object that consists of a set of actions that will be invoked on a receiver, we need a client that initiates the process.
- Command – The command object provides an execute method that is responsible for encapsulating the actions and can be called to invoke the receiver.
- Invoker – Invoker is responsible for calling the command object’s execute method.
- Receiver – Receiver performs the set of actions it is intended to do. Let us straight dive into the code part, so that these terms do not haunt you till the end and you will better understand their responsibilities.
Read also: Decorator design pattern in java with examples.
Command Design Pattern Example
Think of a car. You have decided to create a device that will automatically switch on the lights of your car and also open the driver seat door. These functionalities will be performed by the remote device itself. If you press the light-on button, the light will be switched on and if you press the open-door button, the door will be opened up for you. You can create the device for yourself, we will just show you command design pattern example in java, using this analogy! Our car needs a device (a simple remote control to open the door and switch on the lights) let us create one.
1. Simple Remote Control for our Car
The remote does not know what method it will execute and what functionalities the methods implement. It simply has two methods; one will set the command i.e. whether to switch on the light or open the door or any other functionality and the other executes the method using the execute method from the Command interface. Simple Remote-Control class can be considered as the invoker class.
2. Light and Door functionalities
The light and CarDoor classes implement the required functionalities by defining the methods inside of them You can add your blend to it. They act as the receiver in the command design pattern because ultimately, they are the ones that receive the commands.
3. The Command interfaces
The command interface declares the execute method, and its purpose is simply to execute the method from the Light and CarDoor classes. The Command interface is implemented by the LightOnCommand CarDoorOpenCommand.
4. Implementing the Interface
Both these classes have their own version of the execute method.
5. Testing the Device
To keep things simple, we have created a main method inside the Device class which instantiates the SimpleRemoteControl class that acts as the device we were referring to. So, when the Light-on button is pressed you can think that it sets the command and executes the functionality. The same applies to the Car-Door-Open button.
Now time to talk a little bit about the command design pattern here. See, there is no implementation of light-on command or car-door-open command in the snippet below. The functionalities are being encapsulated by LightOnCommand class and CarDoorOpenCommand class. Also, the methods that do these tasks are not being directly invocated, all these happen when the “client” creates the command object.
You can think of pressing the button on the device as calling the setCommand() and buttonWasPressed() methods from the remote object (device) in the code below. The object does not care what functionality needs to be executed, it only has one purpose, to invocate the methods from the objects that are passed to it. The remote does not know what will be executed, only that it needs to execute.
The client is the Device class. The remote is the invoker that is passed the command object that can be used to make requests. Light Class is the Receiver of the request.
Okay, so what is the motivation behind this approach?
Read also: Factory Design Patterns in Java.
Command Design Pattern Motivation
Well, the command design pattern motivation comes from the following problem:
Hard wired requests should not be implemented i.e. we do not want to couple the invoker of a request to a particular request. For example, Light class to be called directly for its methods, or open-door class for its methods. This approach makes the classes very dependent on each other. We don’t want that; it makes our implementation in-flexible and we cannot specify requests at run time. This is not the only class design pattern motivation that has led us to follow this approach. Software Industry faces and has faced a lot of issues, the command design pattern helped in solving. We have hinted out one such in the introduction section, related to operating systems.
Where Else Is the Command Design Pattern Used?
Since the command design pattern gives us a way to encapsulate invocation that means our invoker can invoke any sort of method without having to know anything about it. The pattern can be extended to use in cases where transactional processes happen. Although database management systems have a more advanced semantics behind the transactions, we can create our own transactions using the command design pattern by adding a set of operations so that all operations complete or none of them do.
Web servers also make use of the command design pattern by making use of a queue of processes that need to be executed in order. There may be several types of requests that need to be invoked and returned back to the client. This example is the same in spirit as the operating system’s one.
Opinions expressed by DZone contributors are their own.