Amit Kumar Mondal bio photo

Amit Kumar Mondal

Java Enthusiast

Email Facebook Google+ LinkedIn Github

Overview

Overview

I have previously posted few articles on implementing some useful patterns using the all new Java 8 Lambda Expressions. Today, I am going to discuss about Decorator Pattern

Decorator Pattern

According to the Gang of Four, this pattern is useful when we require to add behavior to the individual object at runtime.

Inheritence

You might be thinking that Inheritence could be the answer. But Inheritence is not suitable to add behaviors at runtime as it is statically applied to the entire class.

Concrete Example

The following example has been taken from SourceMaking.

</a>

Assault gun is a deadly weapon on it’s own. But you can apply certain “decorations” to make it more accurate, silent and devastating

The Problem Domain

Let’s say, in Berlin, Germany, we have an Agency, called Eval. The purpose of this agency is to evaluate residents of Berlin in regard to several validation criteria. The agency has defined several validation criteria to evaluate the residents. After 20 years of its operation, the agency has been acquired by a big firm in Zurich, Switzerland. Now, this big firm wants to add their own validation criteria to evaluate residents of Zurich.

Now, to solve such a problem, we need to develop the application in such a way that it would facilitate extension to add more validators at runtime.

Functional Way

Candidate POJO

public final class Candidate {

	private final String name;

	public Candidate(final String name) {
		checkNotNull(name);
		this.name = name;
	}

	public String getName() {
		return this.name;
	}

	@Override
	public String toString() {
		return MoreObjects.toStringHelper(this.getClass()).add("name", this.name).toString();
	};

}

Crime Evaluator Criteria

public interface CrimeEvaluator {

	public static Candidate evaluate(final Candidate candidate) {
		System.out.println("Evaluating candidate for Crime");
		return candidate;
	}
}

Experience Evaluator Criteria

public interface ExperienceEvaluator {

	public static Candidate evaluate(final Candidate candidate) {
		System.out.println("Evaluating candidate for Experience");
		return candidate;
	}

}

Residence Evaluator Criteria

public interface ResidenceEvaluator {

	public static Candidate evaluate(final Candidate candidate) {
		System.out.println("Evaluating candidate for Residence");
		return candidate;
	}

}

The Client Application

public final class Application {

	@SafeVarargs
	private static Function<Candidate, Candidate> decorateEvaluators(
			final Function<Candidate, Candidate>... evaluators) {
		return Stream.of(evaluators).reduce(Function.identity(), Function::andThen);
	}

	private static void evaluateCandidate(final Candidate candidate, final Function<Candidate, Candidate> evaluator) {
		System.out.println(evaluator.apply(candidate));
	}

	public static void main(final String[] args) {
		final Candidate candidate = new Candidate("AMIT");
		evaluateCandidate(candidate, decorateEvaluators(ResidenceEvaluator::evaluate, CrimeEvaluator::evaluate,
				ExperienceEvaluator::evaluate));
	}

}

Conclusion

Now, as we said, Decorator Pattern is mainly used to add behavior at runtime, here in the aforementioned example, we can create any validator and pass it to the decorateEvaluators method call in Application class.

The decorateEvaluators method accepts variable argument of functional interface Function. The purpose of this method is to combine all the functions to one single Function so that it can directly be applied to the Candidate for evaluation.

This pattern facilitates user to add behaviors to the object but not methods to the object’s actual interface. The Object’s actual interface remains untouched while the responsibilities get added to the object.