Strategy

The strategy design pattern is used to dynamically choose an implementation algorithm, a strategy, at runtime. The pattern is used, for example, to select different business algorithms depending on the circumstances.

We have several possibilities to make use of the strategy pattern, depending on the situation. We can define different implementations of an algorithm as separate classes. Java SE 8 includes the functionality of lambda methods and method references that can be used as a lightweight strategy implementation:

import java.util.function.Function;

public class Greeter {

    private Function<String, String> strategy;

    String greet(String name) {
        return strategy.apply(name) + ", my name is Duke";
    }

    public static void main(String[] args) {
        Greeter greeter = new Greeter();

        Function<String, String> formalGreeting = name -> "Dear " + name;
        Function<String, String> informalGreeting = name -> "Hey " + name;

        greeter.strategy = formalGreeting;
        String greeting = greeter.greet("Java");

        System.out.println(greeting);
    }

}

The example shows that functional interfaces can be used to dynamically define strategies that are applied and chosen at runtime.

In a Java EE environment, we can again make use of CDI dependency injection. To showcase that CDI supports any Java type, we will use the same example with a strategy that is represented by a functional interface. The greeting strategy is represented by the Function type:

public class Greeter {

    @Inject
    Function<String, String> greetingStrategy;

    public String greet(String name) {
        return greetingStrategy.apply(name);
    }
}

A CDI producer method dynamically selects the greeting strategy:

public class GreetingStrategyExposer {

    private Function<String, String> formalGreeting = name -> "Dear " + name;
    private Function<String, String> informalGreeting = name -> "Hey " + name;

    @Produces
    public Function<String, String> exposeStrategy() {
        // select a strategy
        ...
        return strategy;
    }
}

In order to complete the example, let's introduce specific classes for the algorithm implementations. CDI is able to inject all instances of a certain type that can dynamically be selected.

The GreetingStrategy type is selectable after daytime appropriateness:

public interface GreetingStrategy {
    boolean isAppropriate(LocalTime localTime);
    String greet(String name);
}


public class MorningGreetingStrategy implements GreetingStrategy {
    @Override
    public boolean isAppropriate(LocalTime localTime) {
        ...
    }

    @Override
    public String greet(String name) {
        return "Good morning, " + name;
    }
}

public class AfternoonGreetingStrategy implements GreetingStrategy { ... }
public class EveningGreetingStrategy implements GreetingStrategy { ... }

The CDI producer can inject all possible GreetingStrategy instances and select based on their specification:

public class GreetingStrategySelector {

    @Inject
    @Any
    Instance<GreetingStrategy> strategies;

    @Produces
    public Function<String, String> exposeStrategy() {
        for (GreetingStrategy strategy : strategies) {
            if (strategy.isAppropriate(LocalTime.now()))
                return strategy::greet;
        }
        throw new IllegalStateException("Couldn't find an appropriate greeting");
    }
}

The @Any qualifier implicitly exists on any managed bean. Injection points with the Instance type and this qualifier inject all instances that match the corresponding type, here GreetingStrategy. The Instance type allows us to dynamically obtain and qualify instances of a certain type. It implements an iterator over all eligible types.

By providing custom selection logic, we chose an appropriate strategy that is then injected into the greeter.

CDI allows several ways to specify and choose different strategies. Depending on the situation, dependency injection can be used to separate the selection logic from the usage.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.204.0