Design patterns Strategy Pattern Using Java 8 functional interfaces to implement the Strategy pattern


Example

The purpose of this example is to show how we can realize the Strategy pattern using Java 8 functional interfaces. We will start with a simple use case codes in classic Java, and then recode it in the Java 8 way.

The example problem we using is a family of algorithms (strategies) that describe different ways to communicate over a distance.

The Classic Java version

The contract for our family of algorithms is defined by the following interface:

public interface CommunicateInterface {
    public String communicate(String destination);
}

Then we can implement a number of algorithms, as follows:

public class CommunicateViaPhone implements CommunicateInterface {
    @Override
    public String communicate(String destination) {
        return "communicating " + destination +" via Phone..";
    }
}

public class CommunicateViaEmail implements CommunicateInterface {
    @Override
    public String communicate(String destination) {
        return "communicating " + destination + " via Email..";
    }
}

public class CommunicateViaVideo implements CommunicateInterface {
    @Override
    public String communicate(String destination) {
        return "communicating " + destination + " via Video..";
    }
}

These can be instantiated as follows:

CommunicateViaPhone communicateViaPhone = new CommunicateViaPhone();
CommunicateViaEmail communicateViaEmail = new CommunicateViaEmail();
CommunicateViaVideo communicateViaVideo = new CommunicateViaVideo();

Next, we implement a service that uses the strategy:

public class CommunicationService {
    private CommunicateInterface communcationMeans;

    public void setCommuncationMeans(CommunicateInterface communcationMeans) {
        this.communcationMeans = communcationMeans;
    }

    public void communicate(String destination) {
        this.communcationMeans.communicate(destination);
    }
}

Finally, we can use the different strategies as follows:

CommunicationService communicationService = new CommunicationService();

// via phone
communicationService.setCommuncationMeans(communicateViaPhone);
communicationService.communicate("1234567");

// via email
communicationService.setCommuncationMeans(communicateViaEmail);
communicationService.communicate("hi@me.com");

Using Java 8 functional interfaces

The contract of the different algorithm implementations does not need a dedicated interface. Instead, we can describe it using the existing java.util.function.Function<T, R> interface.

The different algorithms composing the family of algorithms can be expressed as lambda expressions. This replaces the strategy classes and their instantiations.

Function<String, String> communicateViaEmail = 
        destination -> "communicating " + destination + " via Email..";
Function<String, String> communicateViaPhone = 
        destination -> "communicating " + destination + " via Phone..";
Function<String, String> communicateViaVideo = 
        destination -> "communicating " + destination + " via Video..";

Next, we can code the "service" as follows:

public class CommunicationService {
    private Function<String, String> communcationMeans;

    public void setCommuncationMeans(Function<String, String> communcationMeans) {
        this.communcationMeans = communcationMeans;
    }

    public void communicate(String destination) {
        this.communcationMeans.communicate(destination);
    }
}

Finally we use the strategies as follows

CommunicationService communicationService = new CommunicationService();

// via phone
communicationService.setCommuncationMeans(communicateViaPhone);
communicationService.communicate("1234567");

// via email
communicationService.setCommuncationMeans(communicateViaEmail);
communicationService.communicate("hi@me.com");

Or even:

communicationService.setCommuncationMeans(
    destination -> "communicating " + destination + " via Smoke signals.." );
CommunicationService.communicate("anyone");