Thursday, December 1, 2011

The Template Method Pattern

The Template Method patter is a simple but very widely used pattern. In fact, if you ever used the XNA framework, you took advantage of the fact that XNA implements a variation of the Template Method pattern perhaps without even being aware of it!
The Template Method pattern allows us to encapsulate algorithms while also being able to delegate some of the steps of the algorithm to subclasses
Before we see how though, let's look at a simple example.

Many of us love our pets or plants and we have to take care of them. One of the responsibilities is feeding them.
An algorithm for feeding a dog may simply involve getting a can of dog food, opening the can and scooping the contents into a bowl.
Feeding a cat could be quite similar. One could get a can of cat food, open the can and scoop it into a bowl.

Let's build some pet-owner classes and see how this might work.
class DogOwner
{
    public void FeedDog()
    {
        CallDogOver();
        GetDogFood();
        GetCanOpener();
        OpenCan();
        FillBowl();
    }

    void CallDogOver()
    {
        Console.WriteLine("Calling dog's name.")
    }

    void GetDogFood()
    {
        Console.WriteLine("Getting a can of dog food.");
    }
    
    void GetCanOpener()
    {
        Console.WriteLine("Getting a can opener");
    }

    void OpenCan()
    {
        Console.WriteLine("Opening can.");
    }
    
    void FillBowl()
    {
        Console.WriteLine("Empty can into bowl.");
    }
}

class CatOwner
{
    public void FeedCat()
    {
        //These two methods have different implementations
        //Depending on the pet!
        CallCatOver();
        GetCatFood();
        //All of these methods are the same as
        //the DogOwner's...
        GetCanOpener();
        OpenCan();
        FillBowl();
    }

    void CallCatOver()
    {
        Console.WriteLine("Making a ticking noise to get the cat's attention.");
    }

    void GetCanOpener()
    {
        Console.WriteLine("Getting a can opener");
    }

    void GetCatFood()
    {
        Console.WriteLine("Getting a can of cat food.");
    }

    void OpenCan()
    {
        Console.WriteLine("Opening can.");
    }
    
    void FillBowl()
    {
        Console.WriteLine("Empty can into bowl.");
    }
}
A big red flag that a design needs to be reworked is code duplication. For the methods that are the same regardless of pet, we're copying the exact same code into the methods; both involve getting a can opener, opening the can and pouring the contents into a bowl and we should to do something about this duplication.
Even the methods that have different implementations are similar: we still get the pet's attention and retrieve some sort of food.
What we'd like is a framework that allows us to avoid code duplication while also allowing for different implementations on some of the methods in the algorithm. The Template Method pattern allows us to do just that.

Following one of our guidelines to program to an interface (or abstract class), let's rework this a little and code an abstract PetOwner class like so,
abstract class PetOwner
{
    //This is called the Template Method.
    public void FeedPet()
    {
        //These are the steps in the algorithm.
        CallPet();
        GetCanOfFood();
        GetCanOpener();
        OpenCan();
        FillBowl();
    }

    //We delegate the implementation of these methods to
    //any class that inherits from it.
    protected abstract void CallPet();
    protected abstract void GetCanOfFood();

    void GetCanOpener()
    {
        Console.WriteLine("Getting a can opener");
    }

    void OpenCan()
    {
        Console.WriteLine("Opening can.");
    }
    
    void FillBowl()
    {
        Console.WriteLine("Empty can into bowl.");
    }
}
Now any class that inherits from PetOwner must implement both the CallPet and GetCanOfFood methods. The subclasses will be responsible for handling these.

Let's code our DogOwner and CatOwner classes now.
class DogOwner : PetOwner
{
    protected override CallPet()
    {
        Console.WriteLine("Calling the dog's name.");
    }

    protected override GetCanOfFood()
    {
        Console.WriteLine("Getting dog food.");
    }
}

class CatOwner : PetOwner
{
    protected override CallPet()
    {
        Console.WriteLine("Making a ticking noise to get the cat's attention.");
    }

    protected override GetCanOfFood()
    {
        Console.WriteLine("Getting cat food.");
    }
}
This seems to be working out well! But what about a gerbil? (for our example gerbil food now comes in tin cans. No analogy is perfect after all!) One doesn't need to get their attention to eat, one simply fills their bowl. But there's still enough similarities so that we should be able to feed a gerbil with our design.

We can do this by making what's called a hook. A hook is simply a virtual method that by default does nothing but subclasses can hook into it and implement their own behavior if they want to.
Changing the PetOwner class just a little:
abstract class PetOwner
{
    public void FeedPet()
    {
        CallPet();
        GetCanOfFood();
        GetCanOpener();
        OpenCan();
        FillBowl();
    }

    //CallPet is now a hook method.
    protected virtual void CallPet() { }
    protected abstract void GetCanOfFood();

    void GetCanOpener()
    {
        Console.WriteLine("Getting a can opener");
    }

    void OpenCan()
    {
        Console.WriteLine("Opening can.");
    }
    
    void FillBowl()
    {
        Console.WriteLine("Empty can into bowl.");
    }
}
Now CallPet is virtual and by default does nothing. We don't have to change our CatOwner or DogOwner classes at all but in our GerbilOwner class we simply do not have to override it.
class GerbilOwner : PetOwner
{
    protected override GetCanOfFood()
    {
        Console.WriteLine("Getting gerbil food.");
    }
}
We don't need to override the hook method since it's in a cage, probably, and knows exactly when you're about to feed it.

Let's add one more hook to this example so that we can pet the animal after feeding.
abstract class PetOwner
{
    public void FeedPet()
    {
        CallPet();
        GetCanOfFood();
        GetCanOpener();
        OpenCan();
        FillBowl();
        PetAnimal();
    }

    //hooks can be overriden if desired.
    protected virtual void CallPet() { }
    protected virtual void PetAnimal() { }

    //abstract methods must be implemented
    protected abstract void GetCanOfFood();

    void GetCanOpener()
    {
        Console.WriteLine("Getting a can opener");
    }

    void OpenCan()
    {
        Console.WriteLine("Opening can.");
    }
    
    void FillBowl()
    {
        Console.WriteLine("Empty can into bowl.");
    }
}
Now our pet owner classes can pet their animals after feeding if they want to.
class DogOwner : PetOwner
{
    protected override CallPet()
    {
        Console.WriteLine("Calling the dog's name.");
    }

    protected override GetCanOfFood()
    {
        Console.WriteLine("Getting dog food.");
    }

    protected override PetAnimal()
    {
        Console.WriteLine("Petting dog on the the head and scratches behind the ears.");
    }
}

//A fish doesn't need to be called
//And petting one isn't pleasant for you or the fish...
class FishOwner
{
    //Again, for our limited example, fish food comes in cans. (gross)
    protected override GetCanOfFood()
    {
        Console.WriteLine("Getting gerbil food.");
    }
}
The Template Method pattern is arguably the simplest and most widely used pattern around. I mentioned how XNA uses it? Well maybe it's apparent to you how by now but let's consider this.
When you make a new Game project, we automatically get a Game1 class which contains methods for loading content, Updating and Drawing.
Underneath the hood there is an algorithm that first calls Initialize() and LoadContent(), and then a game loop which cycles through the Update() and Draw() methods until the game exits.
The pseudo code might look something very similar to this:
class Game
{
    public void Run()
    {
        Initialize();
        LoadContent();

        //do game loop until we exit the game.
        Update();
        Draw();
    }

    //In this version of the Template Method they're all hooks!
    virtual void Initialize() { }
    virtual void LoadContent() { }
    virtual void Update() { }
    virtual void Draw() { }
}
The same thing applies to GameComponent and DrawableGameComponent.
The methods you see when you first start a game aren't the only hook methods your game can hook into as well, just put your cursor somewhere in the class (but outside a method). And type in 'override'. You'll see a whole slew of things you can override and handle in your own way. Many have default behaviors (called using the base keyword) so watch out for that if you start getting bugs.

That covers the Template Method pattern, a simple but powerful pattern that encapsulates the steps of an algorithm while being able to delegate some of those steps in the algorithm to subclasses.
There are, of course, many variations of the pattern that may not even quite resemble what I've shown you but the idea and purpose is always the same

Hope you enjoyed the article!

No comments :

Post a Comment