Refactoring Strategy Design Pattern with Lambdas

In this post, I would like to explain how to refactor Strategy Design Pattern using lambda expressions?. This post may help in some situations like if we have implemented Strategy Design Pattern in our projects using JDK 6 or 7.
Now we want to use JDK 8 then we can refactor implementation of Strategy Design Pattern using lambda expressions or we newly implement Strategy Design Pattern using lambda expressions in our projects.
Let's understand this refactoring technique with detail example.
If you want to revise or read the Strategy Design Pattern then visit: Strategy Design Pattern.
If you want to revise or read the lambda expressions then visit: lambda expressions
Strategy Design Pattern can be written in a more concise way of using lambda expressions.
The Strategy Design Pattern states that it is a common solution for representing a family of algorithms and letting you choose among them at runtime.
You can apply this pattern to a multitude of scenarios, such as validating an input with different criteria, using different ways of parsing or formatting an input.
  • An interface to represent some algorithm (the interface Strategy)
  • One or more concrete implementations of that interface to represent multiple algorithms (the concrete classes ConcreteStrategyA, ConcreteStrategyB and ConcreteStrategyC).
  • One or more clients that use the strategy objects.
Let's write source code without lambda and with lambda expressions.

Strategy Design Pattern: Without  Using Lambda Expressions

Let’s say we’d validate whether a text input is properly formatted for different criteria (for example, it consists of only lowercase letters or is numeric). You start by defining an interface to validate the text (represented as a String):
    interface ValidationStrategy {
        public boolean execute(String s);
    }
Second, lets/'s define one or more implementation(s) of that interface:
pulic class IsAllLowerCase implements ValidationStrategy {
      public boolean execute(String s){
          return s.matches("[a-z]+");
      }
}
pulic class IsNumeric implements ValidationStrategy {
      public boolean execute(String s){
          return s.matches("\\d+");
      }
}
Let's use these different validation strategies in our program.
 public class Validator{
        private final ValidationStrategy strategy;
        public Validator(ValidationStrategy v){
            this.strategy = v;
        }
        public boolean validate(String s){
            return strategy.execute(s); }
    }
Let's test this Pattern using main method.
public static void main(String[] args) {
        // old school
        Validator v1 = new Validator(new IsNumeric());
        System.out.println(v1.validate("aaaa"));
        Validator v2 = new Validator(new IsAllLowerCase ());
        System.out.println(v2.validate("bbbb"));

  }
Note that in order to apply lambda expression, the Strategy interface should be Functional Interfaces.

Strategy Design Pattern: Using Lambda Expressions

By now we should recognize that ValidationStrategy is a functional interface(in addition, it has the same function descriptor as Predicate<String>). This means that instead of declaring new classes to implement different strategies, we can pass lambda expressions directly, which are more concise:
 // with lambdas
 Validator v3 = new Validator((String s) -> s.matches("\\d+"));
 System.out.println(v3.validate("aaaa"));
 Validator v4 = new Validator((String s) -> s.matches("[a-z]+"));
 System.out.println(v4.validate("bbbb"));
As you can see, lambda expressions remove the boilerplate code inherent to the strategy design pattern. If you think about it, lambda expressions encapsulate a piece of code (or strategy), which is what the strategy design pattern was created for, so I recommend that you use lambda expressions instead for similar problems.

Related posts


Comments