DEV Community

jzfrank
jzfrank

Posted on

HFDP(6) - Command Pattern

In this post we discuss the Command Pattern.

Say the IoT is really getting its trend. A company has designed a set of electronics like Light, GarageDoor, CeilingFan etc., that could be controlled by a program. Now you want to design an app for the client (the house owner, the resident), how should you hide the details of the electronics, while making it flexible enough for the client to customize their needs?

To better appreciate the problem, imagine you are a resident. Wouldn't it be nice to have a remote controller, which allows you to open/close light by simply pressing a button? Or make the garage door up/down, or make the ceiling fan on/off by simply pressing a button? But you do not want to go into the dirty details of each class: yeah, to turn the light on, somewhere needs to call light.on(); to open the garage door, somewhere needs to call garageDoor.up()... But it should not be our lovely, innocent clients to call them, right? We just want to hide the details and reduce coupling. What if at one time we have renamed light.on() api to light.turnOn()? Then the client has to change their code, which is probably the last thing we want it to happen!

Luckily, questions like this have been encountered many times, there are sound wisdoms to the rescue. Let's introduce the protagonist of today: the Command Pattern.

Formal Definition

The Command Pattern encapsulates a request as an object, thereby letting you parametrize other objects with different requests, queue or log requests, and support undoable operations.

Class Diagram

Command Pattern

What consists of the command pattern? an interface called Command that supports execute() and undo(); ConcreteCommand that implements Command interface and binds Receiver with its action(); An Invoker that will call execute() of a certain command; Lastly, of course our Client, which should create a ConcreteCommand and setting its Receiver.

Explained in a real example

To make things less abstract, let's go back to our example of Light, GarageDoor etc. We will have an interface Command. As for the ConcreteCommand, we may have TurnLightOnCommand class, which should be initialized with a Light instance (Receiver), inside its execute() method, it writes something like public void execute() {light.on();}. Similar logic goes for undo() method. Other classes that implements Command include TurnLightOffCommand, OpenGarageDoorCommand, CloseGarageDoorCommand. What the client (again, resident of the house) should do is to create a concrete command and set its receiver (TurnLightOnCommand and lightInLivingRoom). The remote controller would be the Invoker. The user should put their commands to corresponding buttons (put turnLightInLivingRoomCommand to button 1, for example.)

remote controller

A less down-to-earth but relevant example

Imaging a job queue: you add commands to the queue. The queue will finish command one by one. The command may be financial computation, network requesting, etc., but the queue does not need to know which one is which, because they all have implemented interface Command so have execute(), the queue just needs to invoke that method.

That's the big picture of the Command Pattern. See you next design pattern!

Top comments (0)