Let us focus on the non-implementation aspect of the command design, and some main reasons for using the Command desing pattern grouped in two major categories:
Hide implementation
In most programming, you'll want to hide away implementation so that when looking at the top-most problem, it consists of a comprehensible subset of commands/code. I.e. You don't need/want to know the gory details of how a light is switched on, or a car is started. If your focus is to get the car started, you don't need to understand how the engine works, and how it needs fuel to enter the engine, how the valves work, ...
Indicating the action, not how it is done
A command gives you this kind of view. You'll immediately understand what the
TurnLightOn command does, or StartCar . Using a command you'll hide the details of how something is done, whilst clearly indicating the action which is to be executed.Allow changing of inner details
In addition, lets say you later on rebuild your entire
Light class, or a Car class, which requires you instantiate several different objects, and possibly you need to something else before actually doing your wanted operation. In this case if you had implemented the direct access method, in a lot of places, you would need to change it in all places where you've coded it beforehand. Using a command, you can change the inner details of how to do stuff without changing the calling of the command.Possible command extensions
Using a Command interface gives you an extra layer between the code using the command, and the code doing the actual action of the command. This can allow for multiple good scenarios.
Security extension, or interface exposure
Using a command interface, you can also limit access to your objects, allowing you to define another level of security. It could make sense to have a module/library with a fairly open access so that you could handle internal special cases easily.
From the outside, however, you might want to restrict the access to the light so that it is only to be turned on or off. Using commands gives you the ability to limit the interface towards a class.
In addition if you want, you could build a dedicated user access system around the commands. This would leave all of your business logic open and accessible and free of restrictions, but still you could easily restrict access at the command level to enforce proper access.
Common interface to executing stuff
When building a sufficient large system, commands gives a neat way to bridge between different modules/libraries. Instead of you needing to examine every implementation detail of any given class, you can look into which commands are accessing the class.
And since you are leaving out implementation details to the command itself, you could use a common method to instantiate the command, execute it and review the result. This allows for easier coding, instead of needing to read up on how to instantiate that particular
Light or Car class, and determining the result of it.Sequencing of commands
Using commands, you can also do stuff like sequencing of commands. That is since you don't really matter if you are executing the
TurnOnLight or StartCar command, you can execute sequences of theses as they are executed the same way. Which in turns can allow for chains of commands to be executed, which could be useful in multiple situation.
You could build macros, execute sets of commands which you believe are grouped together. I.e. the command sequence:
UnlockDoor , EnterHouse , TurnOnLight . A natural sequence of commands, but not likely to made into a method as it uses different objects and actions.Serialisation of commands
Commands being rather small in nature, also allows for serialisation quite nicely. This is useful in server-client context, or program-microservice context.
The server (or program) could trigger a command, which then serialises the command, sends it over some communication protocol (i.e. event queue, message queue, http, ... ) to someone actually handling the command. No need to first instantiate the object at the server, i.e. a
Light which could be light-weight (pun intended), or a Car which could be a really large structure. You just need the command, and possibly a few parameters.
This could be a good place to introduce to the CQRS - Command Query Responsibility Separation pattern for further studies.
Tracking of commands
Using the extra layer of commands in your system could also allow for logging or tracking commands, if that is a business need. Instead of doing this all over the place, you can gather tracking/logging within the command module.
This allows for easy changes of logging system, or addition of stuff like timeing, or enabling/disabling logging. And it's all easily maintained within the command module.
Tracking of commands also allows for allowing undo actions, as you can choose to re-iterate the commands from a given state. Needs a little bit of extra setup, but rather easily doable.
In short, commands can be really useful as they allow connection between different parts of your soon-to-be-large program, as they are light-weight easily remembered/documented and hides the implementation details when so needed. In addition the commands allows for several useful extensions, which when building a larger system will come in handy: i.e. common interface, sequencing, serialisation, tracking, logging, security.
There're couple of benefits of Command pattern that I've experienced. But first of all, I would like to remind that as all other patterns this pattern is also to increase code readability and bring some common understanding to your (probably) shared code base.
I use this pattern to transition from a method-oriented interface to a command-oriented interface. That means, I'm encapsulating method calls into concrete commands along with necessary data. It makes the code more readable yes but more importantly I can treat methods as objects which lets you easily add/remove/modify commands without increasing the complexity of the code. So it makes it easy to manage as well easy to read.
Secondly, since you've your methods as objects, you can store/queue them to execute them later. Or to cancel them even after you've executed them. This is where this pattern helps you to implement "Undo".
Finally, command pattern also used to decouple command execution and commands themselves. It's like a waiter doesn't know about how to cook the orders that he received. He doesn't care. He doesn't have to know. If he'd know that, he'd be working as a cook as well. And if the restaurant owner wants to fire the waiter, he/she ends up with having no cook as well. Of course this definition is not special or related to command pattern only. That's explains why we need decoupling or dependency management in general.
|
Tuesday, 13 June 2017
Why should I use the command design pattern while I can easily call required methods?
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment