Template Method

The Template Method is discussed in chapter eight of Head First Design Patterns, here is some notes on this pattern that I jotted down while I was reading that fun book.

This pattern defines the structure of an algorithm in a method, deferring the implementation of some of its steps to the subclasses. In this way we have a defined algorithm that could be partially redefined in its subclasses.

We define an AbstractClass in which we have a templateMethod() and a few abstract method primitiveOperationX(), where X is in [1..n]. Each ConcreteClass extending AbstractClass would implement the primitive operations, giving its own version of the original template method.

As an example we see an application that emulates the generation of coffee and tea cups. For this beverages the recipes are very close, but not identical. Using the Template Method pattern we can extract the similarity in a base class and let the derived classes complete the job.

The abstract class:
public abstract class CaffeineBeverage {
    public final void prepare() { // 1
        boilWater();
        brew();
        pour();
        if(extrasRequired()) // 4
            addExtras();
    }

    protected abstract void brew(); // 2
    protected abstract void addExtras();

    private void boilWater() { // 3
        System.out.println("boiling water");
    }

    private void pour() {
        System.out.println("pour");
    }

    protected boolean extrasRequired() { // 4
        return true;
    }
}
1. prepare() is the templateMethod. It is declared final, since we don't want the subclass to redefine it.
2. brew() and addExtras() are primitiveOperations, they are abstract and so they have to be defined by the derived classes.
3. boilWater() and pour() are static parts of the algorithm, so they are private method of this class, they can't be changed by the derived classes.
4. extrasRequired() is a hook. A hook is method that has a default implementation in the AbstractClass but could be redefined by a ConcreteClass to provide a variation in the template method.


Any derived class from the AbstractClass has just to override the primitive operations. The rest of the job is done by the AbstractClass. Let's see a couple of them:
public class Coffee extends CaffeineBeverage {
    private boolean extras;

    public Coffee(boolean extras) {
        this.extras = extras;
    }

    @Override
    protected boolean extrasRequired() { // 1
        return extras;
    }

    @Override
    protected void brew() {
        System.out.println("dripping coffee through filter");
    }

    @Override
    protected void addExtras() {
        System.out.println("adding sugar and milk");
    }
}

public class Tea extends CaffeineBeverage {
    @Override
    protected void brew() {
        System.out.println("steeping the tea");
    }

    @Override
    protected void addExtras() {
        System.out.println("adding lemon");
    }
}
1. the Coffee class redefine the hook, providing a way to decide if the object should have extras.

No comments:

Post a Comment