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
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.)
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)