Command pattern

Example
Suppose we have 2 calculation tasks to do, e.g. add and substract a number. We could use a Calculator to do it:


public class Calculator {
  int currentValue = 0;

  public int add(int valueToAdd) {
    currentValue += valueToAdd;
    return currentValue;
  }

  public int substract(int valueToSubstract) {
    currentValue -= valueToSubstract;
    return currentValue;
  }
}

We could run it as from the Client via CalculationInvoker:

public class Client {

  public static void main(String[] args) {
    CalculationInvoker invoker=new CalculationInvoker();
    System.out.println(invoker.invoke(add, 5));
   System.out.println(invoker.invoke(substract, 3));
  }
}

public class CalculationInvoker {

  Calculator calculator = new Calculator();

  public int invoke(Operation op, int value) {
    switch (op) {
    case add:
      return calculator.add(value);


    case substract:
      return calculator.add(value);

    default:
     throw new RuntimeException("Invalid operation"+op);
    }
  }
}

The result is:
5 (0+5=5)
2 (5-3=2)

This would do its job.

However, suppose we would like to decouple tasks invocation from the task execution (handling the invocation). So in our case decouple CalculationInvoker from the Calculator, so that the invoker will not be aware of actual implementation of the task handling, e.g. one system puts tasks on the queue and the second system is resposible for the task execution.
Moreover, we want the invoker to be able to keep history of executed tasks, execute again last 4 tasks in variant order, or undo last execution. We need a callback functionality.

The solution is to encapsulate a task (request) behind a Command interface:

public interface Command {

    public int execute();
}

The CalculationInvoker would contain a list of Command objects as history. In order to decouple CalculationInvoker from the Calculator we would change the invoke method to accept Command as a parameter. The particular implementation of the Command interface would wrap Calculator and set the reference to Calculator via constructor from the Client (not from the Invoker anymore).

public class CalcCmd implements Command {

  private final Calculator calculator;
  private final int value;
  private Operation op;

  public CalcCmd(Operation op,int value,Calculator calc)
  {
    this.op = op;
    this.value = value;
    this.calculator = calc;
  }

  public int execute() {
    switch (op) {
    case add:
      return calculator.add(value);
    case substract:
      return calculator.substract(value);
    default:
     throw new RuntimeException("Invalid operation"+op);
    }
  }
}

public class Client {

  public static void main(String[] args) {
    CalculationInvoker invoker=new CalculationInvoker();
    Calculator c = new Calculator();
    out.println(invoker.invoke(new CalcCmd(add,5, c)));
out.println(invoker.invoke(new CalcCmd(substract,5,c)));
  }
}

The CalculationInvoker is now decoupled from Calculator:

public class CalculationInvoker {

  private int index = 0;
  private List<Command> cmds = new ArrayList<Command>();


  public int compute(Command command) {
    calcCmds.add(command);
    index++;
    return command.execute();
  }


  public int redo(int opsCount) {
    if (opsCount > index)
     throw new RuntimeException("Cannot redo more than "
      + index +" last operations, requested "+opsCount);

    int result = 0;
    for (int i = 1; i <= opsCount; i++) {
      Command calcCmd = calculatorCommands.get(index-i);
      cmds.add(calculatorCommand);
      result = calcCmd.execute();
    }
    index += opsCount;
    return result;
  }
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s