We have outlined Decorator pattern in a previous post. Decorators implement an interface and besides that wrap an implementation of that interface. So the main purpose is to enrich the existing functionality. Decorator pattern is a better alternative for adding new functionality than inheritance. So we will investigate reusable forwarding decorators to promote the benefits of decorator pattern.

Problem

Let’s say, we have an interface with multiple methods, like java.util.List. Decorators should implement whole interface and add new functionality to some of the methods. If we need additional functionality for a small subset of methods, then other methods will just delegate the operation to the wrapped implementation. If multiple decorators present the same behavior, this will lead to code duplication.

What can we do to solve this issue?

Solution

We can combine decorator pattern with inheritance. We can define a base decorator class which just forwards calls to the wrapped instance.

So real decorators can extend this base class and just override needed methods to add new functionality.

We will use Animal interface.

public interface Animal {

    void walk();

    void run();

    void eat(String meal);

    Animal breed(Animal animal);

    void sleep();
}

 

Dog implements Animal interface.

public class Dog implements Animal{

    @Override
    public void walk() {
        System.out.println("Dog is walking.");
    }

    @Override
    public void run() {
        System.out.println("Dog is running.");
    }

    @Override
    public void eat(String meal) {
        System.out.println("Dog is eating.");
    }

    @Override
    public Animal breed(Animal animal) {
        System.out.println("Dog is breeding.");
        return new Dog();
    }

    @Override
    public void sleep() {
        System.out.println("Dog is sleeping.");
    }
}

 

ForwardingAnimal class is the base decorator and it will just delegate calls. Note that it is abstract and  cannot be instantiated.

public abstract class ForwardingAnimal implements Animal {

    private final Animal delegate;

    public ForwardingAnimal(Animal delegate) {
        this.delegate = delegate;
    }

    @Override
    public void walk() {
        delegate.walk();
    }

    @Override
    public void run() {
        delegate.run();
    }

    @Override
    public void eat(String meal) {
        delegate.eat(meal);
    }

    @Override
    public Animal breed(Animal animal) {
        return animal.breed(animal);
    }

    @Override
    public void sleep() {
        delegate.sleep();
    }
}

 

By using this base decorator, we can develop a decorator that counts breeding occurrences. BreedingAwareDecorator extends ForwardingAnimal and just overrides breed(Animal animal) method.

public class BreedingAwareDecorator extends ForwardingAnimal {

    private final AtomicInteger breedingCount = new AtomicInteger();

    public BreedingAwareDecorator(Animal animal) {
        super(animal);
    }

    @Override
    public Animal breed(Animal animal) {
        Animal baby = super.breed(animal);
        System.out.println("Breeding count: " + breedingCount.incrementAndGet());
        return baby;
    }
}

 

A sample invocation is as follows:

public class ClientMain {

    public static void main(String[] args) {
        Animal dogDecorator = new BreedingAwareDecorator(new Dog());
        dogDecorator.breed(new Dog());
        dogDecorator.breed(new Dog());
        dogDecorator.breed(new Dog());
    }
}

Output:

Dog is breeding.
Breeding count: 1
Dog is breeding.
Breeding count: 2
Dog is breeding.
Breeding count: 3

Source Code

Source code can be found on Github.

Real World Examples

Guava library has forwarding decorator implementations like ForwardingList, ForwardingMap and ForwardingSet.

Leave a Reply

Close Menu