Command Pattern using Java 8 Lambdas

I have been looking at how to improve my knowledge of Design Patterns and at the same time sharpen my Java 8 skills too. I have begun to realize that one can combine the two and also realized that Java 8 Lambdas are extremely powerful.

In this post, we are going to take a look at how the implementation of the Command Design Pattern can be simplified using Java 8 Lambdas.

I have written another blog where you can understand the essence of the Command Design Pattern.

The example we are going to refactor using Java 8 Lambdas is from here. This article on the tutorialspoint site refers to the typical way of implementing the pattern. You must take a look at it to get a basic understanding of the domain/problem at hand. The following is not a UML but I have shown the main components for the example mentioned.

 

CommandPatternWithoutClient

In short , BuyStock and SellStock are 2 commands which implement the Order interface. Stock is the recipient and finally the Broker is the invoker. The Broker class deals only with the Order interface and has no idea about the concrete commands.

Let us implement the same using Java 8 Lambdas. The Order interface is a Functional interface and each ConcreteCommand above is really a function. Do we really a class to represent each Command ? Well, take a look at the client code now using Lambdas:


public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
Broker broker = new Broker();
broker.takeOrder(() -> abcStock.buy());
broker.takeOrder(() -> abcStock.sell());
broker.placeOrders();
}
}

The Broker,Order interface remain the same and so does the Stock class. We can get rid of the individual Concrete Commands (BuyStock, SellStock) classes.

What we have done is actually passed behavior to the takeOrder method. This works as the Order interface has a method execute which takes no parameters and returns void. And hence () -> abcStock.buy() is a lambda expression which takes no parameters and returns void.

To understand this pattern better,  let us extend our problem. Imagine that in the same system, we had to sell Bonds too. The process of buying/selling stocks is different from bonds. With the Broker and the Order interface, the system can easily be extended with minimal changes.

NewCommandPattern

We added 2 more classes BuyBond and SellBond which implement the Order interface. These commands would invoke the Bond class( Receiver) which would perform the task of either buying or selling bonds. The Broker class remains untouched as it deals with only the Order Interface. Well, using Java 8 Lambdas, we don’t need the BuyBond or SellBond classes either.


//Client
public class CommandPatternDemo {
public static void main(String[] args) {
//Stock
Stock abcStock = new Stock();
Broker broker = new Broker();
broker.takeOrder(() -> abcStock.buy());
broker.takeOrder(() -> abcStock.sell());
//Bond
Bond bond = new Bond();
broker.takeOrder(() -> bond.buyBonds());
broker.takeOrder(() -> bond.sellBonds());
broker.placeOrders();
}
}

The Command pattern can be implemented easily using Lambdas. One could argue that the Order interface has just 1 method and we haven’t considered the undo and redo commands in the Command Design pattern. We can always fall back on the typical implementation of the pattern in case we need an undo and redo in addition to the execute functionality.

Having said that, do we always need an Order interface which acts as the Command interface ? How about using the Runnable interface instead  to run all the commands?  It could affect the readability of the code a little bit but otherwise the use of Java 8 Lambdas really makes the implementation easy and powerful at the same time.

Understanding the Command Design Pattern

Let us forget all design patterns for a moment and let us try to solve a simple problem using basic Java programming knowledge.

Problem: I would like to collect tasks to be executed later.

Let us break this down:

  1. The first part is collecting tasks –  this would mean using some kind of a storage which would add tasks together in a data structure. In Java, this can be done using  a Collection. So we need to maintain a Collection<Something>.
  2. Well a better idea would be a List<Something>. A List would be more specific.
  3. What is this Something ? It is a Task ! Okay,  a List<Task> ?
  4. That gives birth to a class Task, now we have a List<Task> to which we can add a task.
  5. Let us get more specific, let us begin with an ArrayList, this would be List<Task> tasks = new ArrayList<>()
  6. But this Task could be different types of tasks. Each “type” of Task… Each “type” of Task…List is generic, it is an interface,  ArrayList, LinkList are different “types” of List. So what next ?
  7. Refactor Task to an interface, and let each “type” of Task be a class which implements the interface Task.
  8. With this in place, we can add any type of Task to the tasks arraylist above. Task1,Task2….Taskn implements Task.
  9. As we are now done with collecting tasks, let us turn to the second part of running the tasks. The interface Task should have a method, let us call it executeTask(). Each type of Task will now override the executeTask() and perform it’s own task.
  10. To run each task – loop through each task and simply call the executeTask method.

for(Task task : tasks) {
task.executeTask();
}

In fact, the above for loop can be executed by using the Runnable interface/Thread class.

Let us turn our attention to the UML of actual Command Design Pattern :

 

Command_Pattern

Each type of Task is really a ConcreteCommand. The Command interface is really the same Task interface. The Invoker is a class which executes the for loop above and maintains a list of tasks/command. The only thing we have not seen is the Receiver, well when each Task/Command is executed, the Receiver will be invoked from each task. It is the work horse of the Command, the object that really does the work.

Advantages of using the Command Pattern:

  1. We can add ‘n’ different commands to the system later but the Invoker remains the same as it only deals with the Interface(Command/Task).
  2. Invoker is not aware of the work horse or the Receiver of each Command. So our system is extensible and loosely coupled.

This is really the essence of the Command Design Pattern.

I have written another blog where I dive into the implementation of the pattern.