java command pattern example with Runnable class :

2019-03-13 15:45发布

问题:

From Examples of GoF Design Patterns in Java's core libraries question, it was quoted that

All implementations of java.lang.Runnable are examples of Command pattern.

As per my understanding of Command pattern,

Client calls Invoker => Invoker calls ConcreteCommand => ConcreteCommand calls Receiver method, which implements abstract Command method.

Have a look at this working example

Command pattern UML diagram from this article is shown as below.

Have a look at this code:

public class ThreadCommand{
    public static void main(String args[]){
        Thread t = new Thread(new MyRunnable());
        t.start();
    }
}
class MyRunnable implements Runnable{
    public void run(){
        System.out.println("Running:"+Thread.currentThread().getName());
    }
}
  1. ThreadCommand is Client
  2. Runnable interface is Command
  3. MyRunnable is ConcreteCommmand
  4. Thread is Invoker with start() method calling ConcreteCommand implementaiton ( which calls run() method)

Is Receiver missing here? Or Does MyRunnable play combined role of ConcreteCommand and Receiver?

回答1:

A Receiver is optional, depending on whether the ConcreteCommmand owns the business logic to be executed. From page 238 of the book,

A command can have a wide range of abilities. At one extreme it merely defines a binding between a receiver and the actions that carry out the request. At the other extreme it implements everything itself without delegating to a receiver at all.

In the original question we see an example with no receiver, because MyRunnable owns the logic to be executed. In two other answers here we see examples delegating to explicit receivers named Receiver and Account.



回答2:

One answer has been posted here and it was removed by author immediately. While reading the answer, I have found solution.

I can simply convert above example to Command pattern UML diagram with one small change.

I can pass Receiver object to MyRunnable ( ConcreteCommand ).

Now I have changed my code as below.

public class ThreadCommand{
    public static void main(String args[]){
        Receiver r = new AC();
        Thread t = new Thread(new MyRunnable(r));
        t.start();
    }
}
class MyRunnable implements Runnable{
    private Receiver receiver;
    public MyRunnable(Receiver r){
        this.receiver = r;
    }
    public void run(){
        receiver.execute();
    }
}
interface Receiver{
    public void execute();
}
class AC implements Receiver{
    public void execute(){
        System.out.println("I am AC");
    }
}
class Fan implements Receiver{
    public void execute(){
        System.out.println("I am Fan");
    }
}

Output:

 java ThreadCommand
 I am AC


回答3:

Wouldn't receiver be...

System.out.println("Running:"+Thread.currentThread().getName()); 

call in the run method. Because that is receiving the action to do when the Runnable runs.



回答4:

I wanna give my two cents...

The original Command pattern separates the Command objects from the Receiver objects because the responsibility of the two sets are different.

Receivers own the business logic of the application. These types should exist outside the pattern. In a practical case Receivers were probably already present in the code base, before commands.

For example, thinking to a bank application, a receiver can be represented by the following type:

public class Account {
    private final double balance;
    // Construct omissis
    public Account deposit(double amount) {
        // Deposit code
    }
    public Account withdraw(double amount) {
        // Withdraw code
    }
}

One of the aims of the command design pattern is that of give a unified, homogeneous and standard way to execute operations on a set of objects (i.e. the receivers). They have not to care how to perform the real business logic. This will limit the reusability of the code implementing business logic.

For this reason, the Commands implementation have to forward the information to Receiver. It follows an example.

public class DepositCommand implements Command {
    private final Account account;
    // An instance of Command should reprenset only a single request
    private final double amount;
    public DepositCommand(Account account, double amount) {
        this.account = account;
        this.amount = amount;
    }

    public void execute() {
        account.deposit(amount);
    }

    // Omissis..
}

In conclusion, imho, the statement present in the accepted answer is not correct.

The receiver is a relic of C/C++ in which the method to be invoked is separated from the object to invoke it on.