Decorator Pattern using Lambda

Decorator Pattern

A decorator pattern allows a user to add new functionality to an existing object without altering its structure.

decorator pattern
Decorator Pattern

Example

BufferedReader buffer = new BufferedReader(new FileReader("file path"));

But rather than being a decorator, this pattern looks ugly.

Using Lambda makes creating a decorator pattern very simple. Let’s look at a very simple example first, before applying the decorator pattern.

import java.util.function.Function


public class Sample {
	public static void print(Integer num, String message, Function<Integer, Integer> func) {
		System.out.println(num + " " + message + ": " + func.apply(num));
	}


	public static void main(String[] args) {
		Function<Integer, Integer> increment = e -> e + 1;
		Function<Integer, Integer> doubled = e -> e * 2;
		print(5, "Incremented", increment);
		print(5, "doubled", doubled);
	}
}

Output

5 Incremented: 6
5 doubled: 10

We can easily call the increment method to increment a number. to double a number we can call the method doubled.

Now lets you want to double a number but increment it first. How are you going to carry this out? One of the answers will be to add a new method incAndThendouble like this.

Function<Integer, Integer> incAndThendouble = e -> (e + 1) * 2;

We may now use the method to get the desired outcome. but this is the incorrect strategy.

The method composition can be used to obtain the desired output that lambda provides out of the box. Let’s explore how to use the method composition.

print(5, "incrented and doubled", increment.andThen(doubled));

Output

5 increented and doubled: 12

Let’s examine how we may use this method’s composition capability to make a Decorator Pattern.

Consider a camera with filters. We could add 0 or more filters to the camera. This is a perfect example of a Decorator Pattern.

import java.awt.Color
import java.util.function.Function;
import java.util.stream.Stream;


class Camera {
	private Function<Color, Color> filter;
	public Camera(Function<Color, Color> ...filters) {
		filter = Stream.of(filters)
					.reduce(Function.identity(),Function::andThen);
	}
	public Color snap(Color input) {
		return filter.apply(input);
	}
}


public class Sample {
	public static void print(Camera camera) {
        //Default color of the snap
		System.out.println(camera.snap(new Color(125, 125, 125)));
	}


	public static void main(String[] args) {

       // Camera with 0 filter
		print(new Camera());

		//Camera with one filter
		print(new Camera(Color::brighter));

        //Camera with two filters
		print(new Camera(Color::brighter, Color::darker));
	}
}
Previous
Next