Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 18 | Comments: 78

filter by tags archive

Design patterns in the test of timeCommand

time to read 2 min | 284 words

The command pattern is a behavioral design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time.

More about this pattern.

I adore this pattern. If this pattern had a paypal account, I would donate it money on a regular basis.

In general, the notion of encapsulating the method call into an object (like the functor sin C++) is an incredibly powerful idea, because is separate the idea of selecting what to invoke and when to invoke it. Commands are used pretty much every where, WPF is probably the most obvious place, because it actually have the notion of Command as a base class that you are supposed to be using.

Other variations, like encapsulating a bunch of code to be executed later (job / task), or just being able to isolate a complex behavior into its own object, is also very useful. I base quite a lot of my architectural advice on the notion that you can decompose a system to a series of commands that you can compose and shuffle at will.

Recommendation: Use it. Often. In fact, if you go so far as to say that the only reason we have classes is to have a nice vehicle for creating commands, you wouldn’t be going far enough.

Okay, I am kidding, but I really like this pattern, and it is a useful one quite often. The thing that you want to watch for are commands that are too granular. IncrementAgeCommand that is basically wrapping Age++ is probably too much, for example. Commands are supposed to be doing something meaningful from the scope of the entire application.

More posts in "Design patterns in the test of time" series:

  1. (21 Jan 2013) Mediator
  2. (18 Jan 2013) Iterator
  3. (17 Jan 2013) Interpreter
  4. (21 Nov 2012) Command, Redux
  5. (19 Nov 2012) Command
  6. (16 Nov 2012) Chain of responsibility
  7. (15 Nov 2012) Proxy
  8. (14 Nov 2012) Flyweight
  9. (09 Nov 2012) Façade
  10. (07 Nov 2012) Decorator
  11. (05 Nov 2012) Composite
  12. (02 Nov 2012) Bridge
  13. (01 Nov 2012) Adapter
  14. (31 Oct 2012) Singleton
  15. (29 Oct 2012) Prototype
  16. (26 Oct 2012) Factory Method
  17. (25 Oct 2012) Builder
  18. (24 Oct 2012) A modern alternative to Abstract Factory–filtered dependencies
  19. (23 Oct 2012) Abstract Factory

Comments

Frans Bouma

Added to that: you can extend commands to implement undo/redo easily, by adding a state and an 'undo' action next to the actual do action. Shameless plug: I implemented this in Algorithmia (OSS, bsd license), where I added a command implementation, which is able to undo actions by the command, and various data structures which are command aware (and thus undo aware) like graphs and lists: http://algorithmia.codeplex.com

Calvin

As well as undo\redo support we've had great success combining the command pattern with the visitor pattern. You have a selection of items and a single command which visits each item in the selection performing the action.

If each visit pushes its undo state on to a stack up can easily undo the operation again.

Khalid Abuhakmeh

Only when I started looking at how you used this pattern in RacoonBlog did I really get why it was so useful to me as a C# .Net developer.

The ability to unit test tasks themselves and then just confirm there existence in other places (MVC Controller) was amazing. Really helped me focus and write meaningful unit tests.

Jimmy Bogard at CodeBetter even goes as far as to turn the command pattern into a Query pattern. He encapsulates complex queries into a class that returns a dataset.

Martin Doms

A nice extension of Command is CompoundCommand (or CompositeCommand, or whatever). A single command that contains an ordered list of commands. Iterate through your commands and call Execute(). Iterate backwards and call Undo(). A nice, single object responsible for a large piece of work, but still following the single responsibility principal by delegating actual meaningful work onto more granular commands.

tobi

Also nice for dependency injection.

Eran Stiller

Ayende - while I do agree with you that the Command pattern is very useful in the various cases you specified, I see it get abused too many times (sometimes really using it as an anti-pattern). For example, I've seen many architects design entire interfaces around the Command pattern (defining a single method which accepts a command derived object), resulting in a very generic definition and implementation - where more specifics would have greatly simplified the code and its maintainability over time.

Anonymous Coward

I'd say let's not exaggerate. Command is extremely useful when you need to generate commands in one place and run them in another. It's also the only decent way I'm aware of to properly implement unlimited undo. But there are situations in which not using command yields smaller and simpler code, which wouldn't have significant benefits if using command.

Anonymous

Do you consider using lambda functions and delegates as an instance of the Command pattern? If you do, then yes, I also use them heavily. They are particularly interesting because you can achieve the same as implementing a interface but not committing to a particular one at compile time.

This is particularly useful when you can not assume a common interface for your objects (such as when they come from a third party library), and implementing several facades would be too much hassle for little benefit. Instead, you can map object methods to delegates on site and have your algorithm control the third-party objects without an explicitly interface definition.

StarTrekRedneck

I completely agree. I see that very frequently the business object of importance is a process, e.g. NotifyShipping, SaveProfile, etc. And, I like how "object-izing" a process is a straight-forward modeling of what computers do: input, processing, output, (storage).

I like what Anonymous had to say about using delegates, although I haven't found wrapping up an external dependency in an interface to be as significant an annoyance for me. I played around with constructor-based dependency injection with delegates as declared dependencies, and I liked that a method didn't have to be tied to the delegate definition, unlike a defined interface. I used StructureMap to inject dependencies on delegates, which worked great, but part of me felt like it wasn't cohesive enough. I guess I haven't completely resolved how I feel about it yet or when and when not to do it.

mcse3010

Don't forget the ever popular MacroCommand where you wrap a series of commands into another command that you can then execute / unexecute as a batch... super useful, indeed.

Ayende Rahien

Anonymous, Lambdas are commands, yes. But in many cases I find it useful to wrap them in a real class, because it make it explicit how / why we capture the parameters for the command to execute.

Yan Cui

Hey Ayende, you really should spend some time with F# if you haven't already. With first class functions, it's a much more natural way to represent and encapsulate units of computation, you can even compose/chain them together to build up more complex computations (such as the combinator-based family of parsers).

I think you'll really like it! :-)

Helen

Is the way you've designed RhinoETL an implementation of the command pattern?

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. Production postmortem: The industry at large - 16 hours from now
  2. The insidious cost of allocations - about one day from now
  3. Buffer allocation strategies: A possible solution - 5 days from now
  4. Buffer allocation strategies: Explaining the solution - 6 days from now
  5. Buffer allocation strategies: Bad usage patterns - 7 days from now

And 2 more posts are pending...

There are posts all the way to Sep 11, 2015

RECENT SERIES

  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    01 Sep 2015 - The case of the lying configuration file
  3. What is new in RavenDB 3.5 (7):
    12 Aug 2015 - Monitoring support
  4. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats