Strategy Pattern using Lambda Expressions in Java 8

Strategy Pattern is one of the patterns from the Design Patterns : Elements of Reusable Object book. The intent of the strategy pattern as stated in the book is:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

In this post I would like to give an example or two on strategy pattern and then rewrite the same example using lambda expressions to be introduced in Java 8.

Strategy Pattern: An example

Consider an interface declaring the strategy:

interface Strategy{
  public void performTask();
}

Consider two implementations of this strategy:

class LazyStratgey implements Strategy{

  @Override
  public void performTask() {
    System.out.println("Perform task a day before deadline!");
  }

}

class ActiveStratgey implements Strategy{

  @Override
  public void performTask() {
    System.out.println("Perform task now!");
  }

}

The above strategies are naive and I have kept it simple to help readers grasp it quickly. And lets see these strategies in action:

public class StartegyPatternOldWay {

  public static void main(String[] args) {

    List<Strategy> strategies = 
        Arrays.asList(
          new LazyStratgey(), 
          new ActiveStratgey()
        );

    for(Strategy stg : strategies){
      stg.performTask();
    }
  }
}

The output for the above is:

Perform task a day before deadline!
Perform task now!

Strategy Pattern: An example with Lambda expressions

Lets look at the same example using Lambda expressions. For this we will retain our Strategy interface, but we need not create different implementation of the interface, instead we make use of lambda expressions to create different implementations of the strategy. The below code shows it in action:

import java.util.Arrays;
import java.util.List;

public class StrategyPatternOnSteroids {
  public static void main(String[] args) {

    System.out.println("Strategy pattern on Steroids");

    List<Strategy> strategies = 
      Arrays.asList(
        () -> {System.out.println("Perform task a day before deadline!");},
        () -> {System.out.println("Perform task now!");}
      );

    strategies.forEach((elem) -> elem.performTask());
  }

}

The output for the above is:

Strategy pattern on Steroids
Perform task a day before deadline!
Perform task now!

In the example using lambda expression, we avoided the use of class declaration for different strategies implementation and instead made use of the lambda expressions.

Strategy Pattern: Another Example

This example is inspired from Neal Ford’s article on IBM Developer works: Functional Design Pattern-1. The idea of the example is exactly similar, but Neal Ford uses Scala and I am using Java for the same with a few changes in the naming conventions.

Lets look at an interface Computation which also declares a generic type T apart from a method compute which takes in two parameters.

interface Computation<T> {

  public T compute(T n, T m);
}

We can have different implementations of the computation like: IntSum – which returns the sum of two integers, IntDifference – which returns the difference of two integers and IntProduct – which returns the product of two integers.

class IntSum implements Computation<Integer> {

  @Override
  public Integer compute(Integer n, Integer m) {
    return n + m;
  }

}

class IntProduct implements Computation<Integer> {

  @Override
  public Integer compute(Integer n, Integer m) {
    return n * m;
  }
}

class IntDifference implements Computation<Integer> {

  @Override
  public Integer compute(Integer n, Integer m) {
    return n - m;
  }
}

Now lets look at these strategies in action in the below code:

public class AnotherStrategyPattern {

  public static void main(String[] args) {

    List<Computation> computations = 
        Arrays.asList(
          new IntSum(), 
          new IntDifference(), 
          new IntProduct()
        );

    for (Computation comp : computations) {
      System.out.println(comp.compute(10, 4));
    }
  }
}

The output for the above is:

14
6
40

Strategy Pattern: Another Example with lambda expressions

Now lets look at the same example using Lambda expressions. As in the previous example as well we need not declare classes for different implementation of the strategy i.e the Computation interface, instead we make use of lambda expressions to achieve the same. Lets look at an example:

public class AnotherStrategyPatternWithLambdas {
  public static void main(String[] args) {

    List<Computation<Integer>> computations = 
          Arrays.asList(
              (n, m)-> { return n+m; },
              (n, m)-> { return n*m; },
              (n, m)-> { return n-m; }
          );
    computations.forEach((comp) -> System.out.println(comp.compute(10, 4)));
  }
}

The output for above is:

14
6
40

From the above examples we can see that using Lambda expressions will help in reducing lot of boilerplate code to achieve more concise code. And with practice one can get used to reading lambda expressions.
 

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You'll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You'll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

One Response to "Strategy Pattern using Lambda Expressions in Java 8"

  1. Alexander K says:

    Mohamed thanks for the article!

    Java8 lambda expressions really reduce the amount of boilerplate code but I think your Java8 and non-java8 examples cannot be considered as equal because in java8 examples you use anonimous strategy implementations and in non-java8 examples you use named classes which can be later reused. So that’s just not the same programs.

Leave a Reply


× nine = 54



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books