1

Going through the Command design pattern I understand that we need to create a Command by setting the context via constructor and then calling the execute method to perform some action on the context. Example:

public class Command implements ICommand {

    Device device;

    public Command(Device device) {
        this.device = device;
    }

    public void execute() {
        this.device.turnOn()
    }
}

I was wondering that with this approach we will be required to create a new Command object for every device object we create. Will it be ok to pass the context and some parameters to the execute method? I am looking for something like:

public class Command implements ICommand {

    public void execute(Device device) {
        this.device.turnOn();
    }

}

Are there any issues with this approach?

1 Answer 1

2

Yes it's absolutely OK to add parameters to the execute() method. It's good to remember how and why the command pattern is used: as a kind of lambda function. In Java 8, it is often no longer necessary to implement a concrete command class because we can use lambdas or method references instead, assuming that ICommand is a @FunctionalInterface.

A command object may save some context in instance fields and a lambda may capture enclosing variables, but the execute method can still take extra parameters and even return values! Just take care to define the Command interface in a way that solves your problems. This could even mean that the Command interface requires multiple methods, in which case it can no longer be a functional interface.

As the traditional example for the command pattern. we might have a GUI where the user clicks on some button. We give the button a Command to execute. The button doesn't supply any data and can't use any return value, so we might define

@FunctionalInterface
interface ButtonCommand {
  void execute();
}

In a completely different scenario, we might have an event driven account balance system. A command will receive the old account state and return the new account state. Then our design might look like:

@FunctionalInterface
interface AccountCommand {
  int execute(int balance);
}

class SendCommand implements AccountCommand {
  int amount;
  public SendCommand(int amount) { this.amount = amount; }
  @Override public int execute(int balance) { return balance - amount; }
}

class ReceiveCommand implements AccountCommand {
  int amount;
  public ReceiveCommand(int amount) { this.amount = amount; }
  @Override public int execute(int balance) { return balance + amount; }
}

class Account {
  int balance = 0;
  public int getBalance() { return balance; }
  public void executeCommand(AccountCommand command) {
    balance = command.execute(balance);
  } 
}

public static void main(String[] argv) {
  AccountCommand[] events = {
    new ReceiveCommand(70),
    // custom command for interest
    balance -> (int)(balance * 1.02),
    new SendCommand(30),
    new SendCommand(20),
  };
  Account acc = new Account();
  for (AccountCommand cmd : events) {
    int oldBalance = acc.getBalance();
    acc.executeCommand(cmd);
    int newBalance = acc.getBalance();
    System.out.println("Account balance changed from " + oldBalance + " to " + newBalance);
  }
}

It may of course be desirable to add further metadata to these commands (such as the transaction counterparty or the authorization for this command). The account could also keep a log of the applied commands, undo commands, and so on. So the command pattern can be more flexible than a simple lambda.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.