Refactoring Chain of Responsibility Pattern with Lambdas

Many existing object-oriented design patterns can be made redundant or written in a more concise way using lambda expressions.

In this post, I would like to explain how to refactor the Chain of Responsibility Pattern using lambda expressions?. This post may help in some situations like if we have implemented the Observer Design Pattern in our projects using JDK 6 or 7.

Now we want to use JDK 8 then we can refactor implementation of Chain of Responsibility Pattern using lambda expressions or we newly implement Chain of Responsibility Pattern using lambda expressions in our projects.

Let's understand this refactoring technique with a detail example.

You can refer there is a separate post for Chain of Responsibility Pattern.

If you want to revise or read the lambda expressions then visit lambda expressions.

The chain of responsibility pattern is a common solution to create a chain of processing objects (such as a chain of operations). One processing object may do some work and pass the result to another object, which then also does some work and passes it on to yet another processing object, and so on.

Chain of Responsibility Pattern: Without Using Lambda Expressions

Let's refer to the above class diagram and write some code to see how this pattern is useful in practice.

Step 1: Generally, this pattern is implemented by defining an abstract class representing a processing object that defines a field to keep track of a successor.

Once it has finished its work, the processing object hands over its work to its successor. In code, it looks like this:
public abstract class ProcessingObject<T> {
     protected ProcessingObject<T> successor;
   
     public void setSuccessor(ProcessingObject<T> successor) {
         this.successor = successor;
     }

     public T handle(T input) {
         T r = handleWork(input);
         if (successor != null) {
            return successor.handle(r);
         }
         return r;
     }

     abstract protected T handleWork(T input);
}
The method handle provides an outline of how to deal with a piece of work. Different kinds of processing objects can be created by subclassing the class ProcessingObject and by providing an implementation for the method handleWork.

Step 2: Let’s look at an example of how to use this pattern. You can create two processing objects doing some text processing:
public class HeaderTextProcessing
  extends ProcessingObject<String> {
    public String handleWork(String text) {
         return "From Raoul, Mario and Alan: " + text;
    }
}

public class SpellCheckerProcessing
  extends ProcessingObject<String> {
    public String handleWork(String text) {
         return text.replaceAll("labda", "lambda");
    }
}
 Step 3: Let's write code to test the above code without lambda expressions.
public static void main(String[] args) {
    ProcessingObject<String> p1 = new HeaderTextProcessing();
    ProcessingObject<String> p2 = new SpellCheckerProcessing();
    p1.setSuccessor(p2);
    String result1 = p1.handle("Aren't labdas really sexy?!!");
    System.out.println(result1);
}

Chain of Responsibility Pattern: Using Lambda Expressions

By using lambda expressions, we can avoid creating subclasses to implement the handleWork() method. We can represent the processing objects as an instance of Function<String, String> or more precisely a UnaryOperator<String>. To chain them we just need to compose these functions by using the andThen method.
public static void main(String[] args) {

 // First processing object
 UnaryOperator<String> headerProcessing =
   (String text) -> "From Raoul, Mario and Alan: " + text;
   
 //Second processing object
 UnaryOperator<String> spellCheckerProcessing =
   (String text) -> text.replaceAll("labda", "lambda");
   
 // Compose the two functions resulting in a chain of operations.
 Function<String, String> pipeline = headerProcessing.andThen(spellCheckerProcessing);
 String result2 = pipeline.apply("Aren't labdas really sexy?!!");
 System.out.println(result2);
}

Related posts


Comments