How does the Command pattern decouple the sender from the receiver?
Asked Answered
B

3

6

The Command pattern has an IReceiver interface with few methods and corresponding to each method there are concrete Command objects (implementing an interface ICommand with execute() method).

I have read that the client knows about the concrete receiver and concrete command and it is usually the client setting up the receiver object in the concrete command object. Then why it is said it decouples the sender and the receiver?

When the client already knows the concrete receiver then I feel this is not loose coupling and also the client in this case can directly call the APIs (methods) on the receiver object.

Brunner answered 8/2, 2016 at 18:42 Comment(0)
C
3

You can think of Command pattern workflow as follows.

  1. Command declares an interface for all commands, providing a simple execute() method which asks the Receiver of the command to carry out an operation.

  2. The Receiver has the knowledge of what to do to carry out the request.

  3. The Invoker holds a command and can get the Command to execute a request by calling the execute method.

  4. The Client creates ConcreteCommands and sets a Receiver for the command.

  5. The ConcreteCommand defines a binding between the action and the receiver.

  6. When the Invoker calls execute the ConcreteCommand will run one or more actions on the Receiver.

Have a look at sample code to understand things in better way.

public class CommandDemoEx{
    public static void main(String args[]){

        // On command for TV with same invoker 
        Receiver r = new TV();
        Command onCommand = new OnCommand(r);
        Invoker invoker = new Invoker(onCommand);
        invoker.execute();

        // On command for DVDPlayer with same invoker 
        r = new DVDPlayer();
        onCommand = new OnCommand(r);
        invoker = new Invoker(onCommand);
        invoker.execute();

    }
}
interface Command {
    public void execute();
}

class Receiver {
    public void switchOn(){
        System.out.println("Switch on from:"+this.getClass().getSimpleName());
    }
}

class OnCommand implements Command{

    private Receiver receiver;

    public OnCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        receiver.switchOn();
    }
}

class Invoker {
    public Command command;

    public Invoker(Command c){
        this.command=c;
    }
    public void execute(){
        this.command.execute();
    }
}

class TV extends Receiver{
    public TV(){

    }
    public String toString(){
        return this.getClass().getSimpleName();
    }
}
class DVDPlayer extends Receiver{
    public DVDPlayer(){

    }
    public String toString(){
        return this.getClass().getSimpleName();
    }
}

output:

java CommandDemoEx
Switch on from:TV
Switch on from:DVDPlayer

To answer your question :

I have read client knows about the concrete receiver and concrete command and it is usually client setting up the receiver object in the concrete command object. Then why it is said it decouples the sender and the receiver

To standardize the words, replace "sender" with "invoker". Now go through the code.

  1. Invoker simply executes the ConcreteCommand (OnCommand in this case) by passing ConcreteReceiver.
  2. ConcreteCommand executes Command through ConcreteReceiver i.e. ConcreteCommand defines binding between Action and Receiver.
  3. If you see the workflow, Invoker does not change with additional commands and you can add business logic in execute() method of Invoker like java.lang.Thread, which has been explained as below.
  4. In this way Client (sender) and Receiver are loosely couple through Invoker, which has knowledge of what command to be executed.

Thread example from this link

You can create Thread by implementing Runnable object.

Thread t = new Thread (new MyRunnable()).start();

=>

 Invoker invoker = new Invoker(new ConcreteCommand());
 invoker.start() 

and you have logic in start() to call ConcreteCommand.execute() which is run() in above case.

start() method will call run() method in Thread. What happens if you directly call run() method directly? It won't be treated as thread.

Like start() method of this thread, you can add some business logic in Invoker.

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
            stop0(throwableFromStop);
        }
    }

private native void start0(); // Native code is not here but this method will call run() method

public void run() {
    if (target != null) {
        target.run();
    }
}

EDIT:

On your last query

Here we are creating the command object, Receiver object and Invoker Object.Then passing the receiver object in the command object and then passing the command object in invoker object. This we do for each Receiver like we do here for TV and DVDPlayer. Also in the method 'main' Object of TV and DVDPlayer are known and in fact are created. We can simply do tvObject.switchOn() and dvdPlayer.switchOn(). How does Command pattern help

Client need not worry about changes in Receiver class. Invoker directly works on ConcreteCommand, which has Receiver object. Receiver object may change siwtchOn() to switchOnDevice() in future. But client interaction does not change.

If you have two different commands like switchOn() and switchOff(), still you can use same Invoker.

Cleancut answered 9/2, 2016 at 15:45 Comment(5)
Thanks Ravindra for answering, but still I am not clear. I want to clear my understanding on as how Command pattern is helpful. Here we are creating the command object, Receiver object and Invoker Object.Then passing the receiver object in the command object and then passing the command object in invoker object. This we do for each Receiver like we do here for TV and DVDPlayer. Also in the method 'main' Object of TV and DVDPlayer are known and in fact are created. We can simply do tvObject.switchOn() and dvdPlayer.switchOn(). How does Command pattern help.Brunner
If switchOn was changed to switchDevice later, client does not require any changes if that command is executed from ConcreteCommand. Like switchOn, you can have switchOff command and can use same invoker for both on and off commands.Cleancut
please refer codereview.stackexchange.com/questions/120029/… I have implemented the Command pattern as per my understanding after studying Command pattern and the comments here. It would be nice to have your review comments over there...Brunner
Updated my comments in that question. Linked this question there :)Cleancut
' Client need not worry about changes in Receiver class. ..... Receiver object may change siwtchOn() to switchOnDevice() in future. But client interaction does not change. ' - if the receiver object changes siwtchOn() to switchOnDevice() , then the client need not worry about the change. But the Concretecommand needs to know it, right ? If yes, then what benefits do you point at here ?Antilles
H
3

Directly from Wikipedia:

The command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time.

Edit

After re-reading the Gang of Four's section on the Command pattern, I thought up a better scenario. Let's say you have a GUI library, which defines the following:

public interface Command {
    public void execute();
}

public class Button {
    private Command command;

    public Button(Command command) {
        this.command = command;
    }

    public void click() {
        command.execute();
    }
}

The Button, in this case, is the receiver of a command, and your code, that creates actual instances of Buttons, is the client. Of course, when you create a button, you have to define some concrete implementations of the Command interface. But the GUI library does not need to know about these classes; all it needs is the interface. This is how the GUI code is decoupled from your code.

Hammering answered 8/2, 2016 at 19:35 Comment(4)
thanks Andrew for the answer. Sorry but still I am not too clear on this. Can you please give a small example as how if command pattern is not used then things become difficult to manage or complexcity is increased or code duplication or any other ill effect if command pattern is not used...Brunner
@Brunner See the edit, I hope it makes more sense. The main idea is that implementation is hidden behind the Command interface, so you don't end up with multiple classes when you only need one. E.g. a RefreshButton and an UndoButton could just be a plain Button, with different Commands to execute.Hammering
Impressive explanation Andrew.. n thanks for the efforts. But I feel above is more like observer pattern. In the above explanation, its more like callback some what miniature form of observer pattern. Here in the example, Command is like an observer registered in the button class. Upon click the call back method 'execute' is called and in the concrete implementation of 'execute()' method actual operations like refresh, undo can be performed. Please correct me if my understanding is wrong...Brunner
Yes, design patterns often have a lot of overlap. This also shows a lot of the features of Strategy, where the actual implementation is hidden behind an interface. The thing that makes Command special is that each command object holds all the information it needs to perform the action. This example doesn't really show that so much, you wanted to see how it decouples code. This was the simplest way I could show it.Hammering
C
3

You can think of Command pattern workflow as follows.

  1. Command declares an interface for all commands, providing a simple execute() method which asks the Receiver of the command to carry out an operation.

  2. The Receiver has the knowledge of what to do to carry out the request.

  3. The Invoker holds a command and can get the Command to execute a request by calling the execute method.

  4. The Client creates ConcreteCommands and sets a Receiver for the command.

  5. The ConcreteCommand defines a binding between the action and the receiver.

  6. When the Invoker calls execute the ConcreteCommand will run one or more actions on the Receiver.

Have a look at sample code to understand things in better way.

public class CommandDemoEx{
    public static void main(String args[]){

        // On command for TV with same invoker 
        Receiver r = new TV();
        Command onCommand = new OnCommand(r);
        Invoker invoker = new Invoker(onCommand);
        invoker.execute();

        // On command for DVDPlayer with same invoker 
        r = new DVDPlayer();
        onCommand = new OnCommand(r);
        invoker = new Invoker(onCommand);
        invoker.execute();

    }
}
interface Command {
    public void execute();
}

class Receiver {
    public void switchOn(){
        System.out.println("Switch on from:"+this.getClass().getSimpleName());
    }
}

class OnCommand implements Command{

    private Receiver receiver;

    public OnCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        receiver.switchOn();
    }
}

class Invoker {
    public Command command;

    public Invoker(Command c){
        this.command=c;
    }
    public void execute(){
        this.command.execute();
    }
}

class TV extends Receiver{
    public TV(){

    }
    public String toString(){
        return this.getClass().getSimpleName();
    }
}
class DVDPlayer extends Receiver{
    public DVDPlayer(){

    }
    public String toString(){
        return this.getClass().getSimpleName();
    }
}

output:

java CommandDemoEx
Switch on from:TV
Switch on from:DVDPlayer

To answer your question :

I have read client knows about the concrete receiver and concrete command and it is usually client setting up the receiver object in the concrete command object. Then why it is said it decouples the sender and the receiver

To standardize the words, replace "sender" with "invoker". Now go through the code.

  1. Invoker simply executes the ConcreteCommand (OnCommand in this case) by passing ConcreteReceiver.
  2. ConcreteCommand executes Command through ConcreteReceiver i.e. ConcreteCommand defines binding between Action and Receiver.
  3. If you see the workflow, Invoker does not change with additional commands and you can add business logic in execute() method of Invoker like java.lang.Thread, which has been explained as below.
  4. In this way Client (sender) and Receiver are loosely couple through Invoker, which has knowledge of what command to be executed.

Thread example from this link

You can create Thread by implementing Runnable object.

Thread t = new Thread (new MyRunnable()).start();

=>

 Invoker invoker = new Invoker(new ConcreteCommand());
 invoker.start() 

and you have logic in start() to call ConcreteCommand.execute() which is run() in above case.

start() method will call run() method in Thread. What happens if you directly call run() method directly? It won't be treated as thread.

Like start() method of this thread, you can add some business logic in Invoker.

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
            stop0(throwableFromStop);
        }
    }

private native void start0(); // Native code is not here but this method will call run() method

public void run() {
    if (target != null) {
        target.run();
    }
}

EDIT:

On your last query

Here we are creating the command object, Receiver object and Invoker Object.Then passing the receiver object in the command object and then passing the command object in invoker object. This we do for each Receiver like we do here for TV and DVDPlayer. Also in the method 'main' Object of TV and DVDPlayer are known and in fact are created. We can simply do tvObject.switchOn() and dvdPlayer.switchOn(). How does Command pattern help

Client need not worry about changes in Receiver class. Invoker directly works on ConcreteCommand, which has Receiver object. Receiver object may change siwtchOn() to switchOnDevice() in future. But client interaction does not change.

If you have two different commands like switchOn() and switchOff(), still you can use same Invoker.

Cleancut answered 9/2, 2016 at 15:45 Comment(5)
Thanks Ravindra for answering, but still I am not clear. I want to clear my understanding on as how Command pattern is helpful. Here we are creating the command object, Receiver object and Invoker Object.Then passing the receiver object in the command object and then passing the command object in invoker object. This we do for each Receiver like we do here for TV and DVDPlayer. Also in the method 'main' Object of TV and DVDPlayer are known and in fact are created. We can simply do tvObject.switchOn() and dvdPlayer.switchOn(). How does Command pattern help.Brunner
If switchOn was changed to switchDevice later, client does not require any changes if that command is executed from ConcreteCommand. Like switchOn, you can have switchOff command and can use same invoker for both on and off commands.Cleancut
please refer codereview.stackexchange.com/questions/120029/… I have implemented the Command pattern as per my understanding after studying Command pattern and the comments here. It would be nice to have your review comments over there...Brunner
Updated my comments in that question. Linked this question there :)Cleancut
' Client need not worry about changes in Receiver class. ..... Receiver object may change siwtchOn() to switchOnDevice() in future. But client interaction does not change. ' - if the receiver object changes siwtchOn() to switchOnDevice() , then the client need not worry about the change. But the Concretecommand needs to know it, right ? If yes, then what benefits do you point at here ?Antilles
R
1

Loose coupling isn't the main goal of Command

Here's the class diagram for the Command pattern from the original Design Patterns book:

Command class diagram

As you said, Client knows about the ConcreteCommand and the Receiver, so there's not decoupling there.

why it is said it decouples the sender and the receiver

My copy of the book doesn't say that's the goal of the Command pattern:

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Andrew's answer touches on the fact that the logic thread is decoupled from the commands. You can maybe better see the loose coupling between Invoker and Command when you refer to the sequence diagram of the pattern described in the Design Patterns:

Command sequence diagram

Many design patterns define a Client that is loosely coupled from the variations (e.g., Visitor, Strategy, Observer, Iterator, etc.). Loose coupling is a benefit to maintainability, so-called design for change. Command is special, since the Client who's protected from changes is Invoker -- it is decoupled from ConcreteCommmand classes. I think that's the classic decoupling you're looking for. Adding new commands will require changing the Client, but shouldn't break Invoker, who only knows the Command abstraction.

I have always thought of the Command pattern as unique, because its main goal seems to be about providing functional requirements: undo, redo, logging, macro-command operations, transactions, etc.


Edit

Regarding IReceiver abstraction and decoupling from Client and concrete Receiver classes: that is possibly just the Strategy pattern being used with Command. I quoted the original book. Lots of variants of patterns exist (Wikipedia is not always a great reference for patterns because of this).

Recourse answered 9/2, 2016 at 15:18 Comment(1)
Thanks for the reply.If there are multiple receivers with different actions like TV: switchON(), setFirstChannel(); AC:switchOn(),setMinTemp(); MusicPlayer:switchOn(),setMaxVolume().If we have all these requests enqueued. In case any new device like Microwave:switchON(),set30SecTimer() needs to be included then simply objects of Microwave can be encapsulated in the object of TimerCommand and it can simply be added in the queue. This way command pattern can be of good help. Please correct if I am wrong.Brunner

© 2022 - 2024 — McMap. All rights reserved.