You can think of Command pattern workflow as follows.
Command
declares an interface for all commands, providing a simple execute() method which asks the Receiver of the command to carry out an operation.
The Receiver
has the knowledge of what to do to carry out the request.
The Invoker
holds a command and can get the Command
to execute a request by calling the execute method.
The Client
creates ConcreteCommands
and sets a Receiver
for the command.
The ConcreteCommand
defines a binding between the action and the receiver.
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.
Invoker simply executes the ConcreteCommand
(OnCommand in this case) by passing ConcreteReceiver.
ConcreteCommand executes Command
through ConcreteReceiver i.e. ConcreteCommand defines binding between Action and Receiver.
- 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.
- 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
.