A common question we get from readers and from students in our Design Patterns Bootcamp course is about using Java lambda expressions with the Strategy Pattern. Our book, Head First Design Patterns, and our course both use Java to demonstrate how to implement a design that incorporates the Strategy Pattern, and one thing some people notice about our example is that our strategies are functional interfaces:

public interface FlyBehavior {
    public void fly();
}
public interface QuackBehavior {
    public void quack();
}

In Java, a functional interface is one that has only one abstract method. In our Duck Simulator example, the flying and quacking strategies are both functional interfaces, which means that the concrete strategies that implement these interfaces can be expressed as lambdas. The traditional way to implement the concrete strategies is to define a separate class, for example Squeak:

public class Squeak implements QuackBehavior {
    public void quack() {
        System.out.println("Squeak");
    }
}

and then create a Squeak instance to assign to a duck, as we do in the Rubber Duck constructor:

public RubberDuck() {
    flyBehavior = new FlyNoWay();
    quackBehavior = new Squeak();
}

Using lambdas, we could replace the Squeak class and the code to create a new Squeak object, with this instead:

public RubberDuck() {
    flyBehavior = new FlyNoWay();
    quackBehavior = () -> System.out.println("Squeak");
}

Lambda expressions are essentially syntactic sugar that replace creating a class that implements a functional interface and an object that instantiates that class. In my opinion, the main benefit of using lambda in this situation is that you reduce the amount of code you need to write, and save writing an entire class file.

However, one thing to keep in mind is code reuse. In this small example, where I’m using this strategy only once (with the RubberDuck), using an lambda expression like this is fine. But what if I’m going to reuse the Squeak functionality over and over again with many ducks?

In that case, we’d be better off defining the Squeak behavior just once, and passing it into the ducks that need to use it. In that scenario we can use Dependency Injection: create the duck behaviors in the DuckSimulator class, and pass the behaviors for the ducks to their constructors. For example, we’d modify each of our Ducks to include a constructor that takes a fly behavior and a quack behavior:

public class RubberDuck extends Duck {	
    public RubberDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
        this.flyBehavior = flyBehavior;
        this.quackBehavior = quackBehavior; 
    }
 
    public void display() {
        System.out.println("I'm a rubber duckie");
    }
}

And then in the DuckSimulator class, we’d first create the behaviors, saving them in variables so we can reuse them for multiple ducks, and then pass those behaviors into any duck that needs them:

FlyBehavior cantFly = () -> System.out.println("I can't fly");
QuackBehavior squeak = () -> System.out.println("Squeak");
RubberDuck rubberDuckie = new RubberDuck(cantFly, squeak);

Now we get the benefit of code reuse and the shorthand of the lambda expression.

Keep in mind, your strategies may be much more complex than our simple duck behaviors, and so many strategies will not be simple functional interfaces. In that case you won’t be able to use lambda expressions as short hand for your strategies and you’ll have to build them the old-fashioned way.

For instance, think of how the Strategy Pattern is used in the Model View Controller compound pattern. Here the Strategy Pattern is used to organize the relationship between the View and the Controller. You can think of the Controller as a strategy (or set of strategies) for how to handle various actions in the View. So, your Controller will likely contain many methods that the View will call, depending on what action the user takes–clicking a button, or choosing a menu option, etc–and so it’s likely that your Controller will be far more complex than a simple functional interface.

To see the complete code for the Duck Simulator, check out the Head First Design Patterns code repository at github.

To see what the Strategy Pattern is and how it works, read Chapter One of Head First Design Patterns.

To understand how the Model View Controller compound pattern uses the Strategy Pattern, read Chapter Twelve of Head First Design Patterns.

To learn lambda expressions in depth, read Chapter 8 of the Java SE 8 Study Guide.

And if you’re a Safari Books Online member, you can sign up for our Design Patterns Bootcamp course at their Live Online Training page.

Don't miss out!!

Don't miss out on brain-friendly WickedlySmart updates early access to books and general cool stuff! Just give us your email and we'll send you something about once a week. 

You have Successfully Subscribed!