By Nelson Suwal on Nov, 30, 2016 in command-design-pattern, design-pattern, ruby, programming
Command design pattern is a behavioural pattern in which obtect are use to encapsulate all the information that need to perform action or trigger an event at later time. This information includes the method name, the object that owns the method and values for the method parameters.
There are four terms associate with the command pattern. They are:
This element really behaves like a client (deciding what to do). Its job is to determine which command to execute, without knowing who will execute it and how it will be executed.
# Invoker class Switch attr_reader :history def execute(cmd) @history ||=  @history << cmd.execute end end # Command Interface class Command attr_reader :light def initialize(light) @light = light end def execute raise NotImplementedError end End # Command for turning on class TurnOnCommand < Command def execute light.turn_on end end # Command for turning off class TurnOffCommand < Command def execute light.turn_off end end # Receiver class Light def turn_on 'the light is on' end def turn_off 'the light is off' end end # Client class LightSwitchClient attr_reader :switch def initialize @lamp = Light.new @switch = Switch.new end def switch_for(cmd) case cmd when 'on' then @switch.execute(TurnOnCommand.new(@lamp)) when 'off' then @switch.execute(TurnOffCommand.new(@lamp)) else puts 'Sorry, I so sorry' end end end client = LightSwitchClient.new puts client.switch_for('on') puts client.switch_for('off') puts client.switch.history
'the light is on'
'the light is off'
['the light is on',the light is off']
Switch class executing the commands and keeping the log of the commands. Command interface accepting the parameter is light in this case. We have two concrete command classes ( TurnOnCommand and TurnOffCommand ). These command classes invokes the methods of the receiver. Receiver does the actual works.Receiver's job is to turn on the light or turn off the light. Client makes the decision which command should created and when to execute the commands.
Now that we have understood how the pattern works, it's time to take a look at its advantages and flaws, too.
There are two extremes that a programmer must avoid when using this pattern:
We must always keep in mind the fact that the receiver is the one who knows how to perform the operations needed, the purpose of the command being to help the client to delegate its request quickly and to make sure the command ends up where it should.
As mentioned above, some implementations of the Command design pattern include parts for supporting undo and redo of actions. In order to do that a mechanism to obtain past states of the Receiver object is needed; in order to achieve this there are two options:
Before running each command a snapshot of the receiver state is stored in memory. This does not require much programming effort but can not be always applied. For example doing this in an image processing application would require storing images in memory after each step, which is practically impossible.
Instead of storing receiver objects states, the set of performed operations are stored in memory. In this case the command and receiver classes should implement the inverse algorithms to undo each action. This will require additional programming effort, but less memory will be required. Sometimes for undo/redo actions the command should store more information about the state of the receiver objects. A good idea in such cases is to use the Memento Pattern.
Another usage for the command design pattern is to run commands asynchronously in background of an application. The invoker runs in the main thread and sends the requests to the receiver which runs in a separate thread. The invoker will keep a queue of commands to be run and will send them to the receiver while it finishes running them.
Instead of using one thread in which the receiver is running more threads can be created for this. But for performance issues (thread creation is consuming) the number of threads should be limited. In this case the invoker will use a pool of receiver threads to run command asynchronously.
When adding new commands to the application we can use the composite pattern to group existing commands in another new command. This way, macros can be created from existing commands.
The main advantage of the command design pattern is that it decouples the object that invokes the operation from the one that know how to perform it. And this advantage must be kept. There are implementations of this design pattern in which the invoker is aware of the concrete commands classes. This is wrong making the implementation more tightly coupled. The invoker should be aware only about the abstract command class.
Suppose a program has a sequence of commands that it executes in order. If each command object has a get_estimated_duration() method, the program can easily estimate the total duration. It can show a progress bar that meaningfully reflects how close the program is to completing all the tasks.
If all user actions are represented by command objects, a program can record a sequence of actions simply by keeping a list of the command objects as they are executed. It can then "play back" the same actions by executing the same command objects again in sequence. If the program embeds a scripting engine, each command object can implement a to_script() method, and user actions can then be easily recorded as scripts.
Don't miss the next one!