6

let's assume that we have command pattern implemented in this way

I am a bit confused about the role of Invoker here. From my point of view:

  1. If we do need history (or any kind of action before command execution), then there is a sense in making this class. But then it breaks Single responsibility principle, yeah? Now it's not only a delegate, it also stores history there.
  2. If we don't need history, I don't see a goal of creating this invoker, that simply performs delegating. Is the only reason for it is just a assumption, that we would need some kind of logic before/after command execution in the future?

Or am I missing something?

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211

4 Answers4

2

Did you read the Wikipedia article you referenced?

Using an invoker object allows bookkeeping about command executions to be conveniently performed, as well as implementing different modes for commands, which are managed by the invoker object, without the need for the client to be aware of the existence of bookkeeping or modes.

The responsibility/purpose isn't delegation, but bookkeeping, so there is no breaking of Single responsibility principle.

You could argue that if the Invoker does both bookkeeping and mode management, it has two responsibilities, but you can separate that inside the invoker, if needed.

Remember, the Command pattern doesn't care about Single responsibility. That's a different pattern, and it's up to you to apply both, if that's what you need.

Andreas
  • 154,647
  • 11
  • 152
  • 247
2

In this particular design pattern, the Invoker optionally does bookkeeping about the command execution.

So I wouldn't worry too much about whether keeping the history is necessary, nor whether that violates the single responsibility principle (if the "bookkeeping" became complicated, the invoker could always delegate bookkeeping to another class).

So why does the Invoker exist at all?

It basically gives you a single point for registering your Command actions that knows as little as possible about the actual problem domain - only how to call execute() on a Command.

Benefits of doing it this way include an easily understandable design pattern and reduced coupling (the Invoker doesn't need to know anything about the Light).

vikingsteve
  • 38,481
  • 23
  • 112
  • 156
2

If we do need history (or any kind of action before command execution), then there is a sense in making this class. But then it breaks Single responsibility principle, yeah? Now it's not only a delegate, it also stores history there.

I fully agree with Andreas answer. If you think that you are executing multiple responsibilities, break them into different methods.

Single Responsibility principle is good to hear but we should not give too much of attention to that principle. If you strictly follow that principle, I am sure that code base is cluttered with too many small classes. I don't think any of big projects in software industry use that principle. The best thing we can do have different methods in same class for different actions.

If we don't need history, I don't see a goal of creating this invoker, that simply performs delegating. Is the only reason for it is just a assumption, that we would need some kind of logic before/after command execution in the future?

The core USP of Command pattern is Invoker. It decouples Client ( Sender) and Receiver.

From oodesign article:

The Client asks for a command to be executed. The Invoker takes the command, encapsulates it and places it in a queue, in case there is something else to do first, and the ConcreteCommand that is in charge of the requested command, sending its result to the Receiver.

I have explained the role of Invoker in below SE question:

Command Pattern seems needlessly complex (what am I failing to understand?)

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
1

from http://www.oodesign.com/command-pattern.html:

The example of the meal order at a restaurant is a very good one when trying to explain better how the pattern works: The waiter (Invoker) takes the order from the customer on his pad. The order is then queued for the order cook and gets to the cook (Receiver) where it is processed.

Meindert
  • 384
  • 2
  • 9