The template behavioral pattern allows your derived classes to change certain aspects of the base class behavior without needing to rewrite everything.
This design pattern is great when you have a complicated set of steps that the base class provides. You can then write derived classes that use the overall set of steps and only need to specialize certain smaller steps. The base class defines the overall structure of how something should be done and calls one or more virtual methods at the right time which a derived class can override.
The overall method in the base class is called the template method because it provides the structure. It acts like a template.
The methods that the derived classes override are called hook methods because they let a derived class insert custom behavior into the process sort of like how a hook can attach itself to something. It’s important to note that the derived classes can’t just insert their code anywhere. This whole pattern starts with the base class defining the overall template and the available hooks. If there are no hooks, then you don’t really have code that follows this design pattern.
There’s another common scenario that the template method can help with. It’s sometimes useful in derived classes to not just override a base class method but to extend a base class method. How does a derived class do this? First the method needs to be virtual so the derived class can override it. Then in the derived class implementation, it does whatever it needs to do and then calls the base class version.
But what happens if a derived class forgets to call into the base class? You end up with only the behavior in the derived class and the extension is lost. How can you make it less likely for this to happen? Just remove the need for the derived class to call the base class in the first place.
Instead of making a virtual method that a derived class overrides to extend, you instead define a normal non-virtual method in the base class. This method will follow the template design pattern and call a virtual method that a derived class can override. The base class performs its own behavior and then calls the virtual method. Or maybe it calls the virtual method and then performs its own behavior. The important part is that it does both. Now, when a derived class overrides the virtual method to extend the behavior, it doesn’t need to call the base class version of the virtual method anymore at all. Listen for more or read the full transcript below.
The basic description says that this pattern allows a base class to define the skeleton or important structure of an algorithm and let derived classes change certain steps.
If you look at some cooking recipes, you’ll notice optional steps or things you might want to do differently. The basic recipe is still valid. Maybe you just want to modify it slightly with an extra ingredient. Or maybe the recipe shows you how to substitute a hard-to-find ingredient with a more common one.
This is exactly what the template design pattern describes. It’s great when you have a complicated set of steps that the base class provides. You can then write derived classes that use the overall set of steps and only need to specialize certain smaller steps. Just like how a chocolate cake recipe describes how to make a chocolate pecan cake. Everything remains the same except for the pecans.
You can also do other things with this pattern. Let’s say that you ONLY want derived classes to change certain steps. The overall structure is placed in a method of the base class called the template method. And whether you’re following the template pattern for extra flexibility or because you want to lock down what can be changed, the parts that can be changed are sometimes called hook methods.
I also want to mention that the template method is just what this type of method and this design pattern is called. It doesn’t have anything to do with generic programming or templates.
The actual implementation of the template design pattern is easy. When you have a base class with a rather involved method that you want to allow derived classes to customize, instead of making the method itself virtual, you put some of the steps in smaller virtual methods that the larger method then calls.
This provides some extra benefits. Not only is the larger method not so large anymore, it becomes easier to read and understand. Those steps that used to live in the larger method now live in a method of their own with a descriptive name. And it reduces code duplication because the derived class doesn’t need to repeat a bunch of code that probably would have been the same anyway.
This pattern reverses the normal direction that methods are called. Normally we consider derived classes that sometimes call base class methods. This pattern describes how to get a base class method to call derived class methods. Now, the base class can’t call a derived class method directly because it knows nothing about the derived class. But the base class can declare a virtual method that it calls. Then when the derived class overrides the virtual method, the base class ends up calling into the derived class.
Back to the chocolate cake example, the pecans won’t just appear in the cake on their own. The base class needs to anticipate the need to allow derived classes to provide their own implementation and create the virtual methods to do so. So a base class for a cake would need to define a virtual method called addExtraIngredients or something like that and make sure to call the method at the right time. Even if the chocolate cake has no extra ingredients, part of being a template method involves calling methods like this at the right time.
I’ll explain some more details about this pattern including a curious trick that actually CAN allow a base class to directly call into a derived class right after this message from our sponsor. Just when you think you’re getting to know C++, along comes a more advanced technique that makes things possible that you thought would never happen, right?
( Message from Sponsor )
Let me highlight another common scenario and show how the template method can help. It’s sometimes useful in derived classes to not just override a base class method but to extend a base class method. How does a derived class do this? Well, first the method needs to be virtual so the derived class can override it. Then in the derived class implementation, it does whatever it needs to do and then calls the base class version. By calling the base class version explicitly, this will route to the next virtual method in the chain of overridden methods. Usually this is the original base class but could be different if there are many derived classes that override the same method more than once.
But what happens if a derived class forgets to call into the base class? The extension is lost. How can you make it less likely for this to happen? Simple. By removing the need for the derived class to call the base class in the first place. Here’s how.
Instead of making a virtual method that a derived class overrides to extend, you instead define a normal non-virtual method in the base class. This method will follow the template design pattern and call a virtual method that a derived class can override. But here’s the important part, it doesn’t just call the virtual method. That would be kinda pointless. It performs its own behavior and then calls the virtual method. Or maybe it calls the virtual method and then performs its own behavior. The important part is that it does both. Now, when a derived class overrides the virtual method to provide some extension, it doesn’t need to call the base class version of the virtual method because the behavior it’s trying to extend is already being managed by the base class.
Okay, now I’m going to bring real templates into this explanation. I hesitate a bit on doing this because I haven’t yet described what they are, how to use them, and why they’re needed. If you don’t fully understand this explanation, don’t worry, I’ll explain templates and generic programming in a future episode. And probably many future episodes. It’s not only a big topic, but this is a rather clever usage of templates. That puts this technique well on the advanced side.
Consider this a mini explanation of templates. The reason I’m explaining this is because what I’m about to explain requires templates in order to work. What this technique allows you to do though is remarkable and directly relates to this design pattern.
Think of a template as a way of specializing a class based on some other class type. It allows you to write code that will work with any type. Need to call a method that needs an int for a method parameter? No problem, right? Just declare a method with this signature. What if you now need the method to take a bool type? Well, you can always overload the method by declaring a new method with the same name only with a bool parameter instead of an int. But if you do this, then you need to duplicate all the code. One version will be for ints and one version will be for bools. Templates allow you to write just one version of your method and leave the exact type of the parameter up to the caller. It’s really a way of getting the compiler to write your code for you. If you end up calling the method with both an int one time and later with a bool, then there will still be two version of the method. The difference is that you only needed to write a template that was used by the compiler to generate both versions. That’s why this feature is called templates. It looks like you’re writing code. But you’re really just writing a template that the compiler will turn into code that works with the types you actually use.
That was a whirlwind explanation of templates. How can we use that to allow a base class to call directly into a derived class when the base class has no idea about any derived class? Sure, we can use virtual methods to do this. But that means that the base class has to declare a virtual method and the derived class needs to override the virtual method. A virtual method gives the base class knowledge about the method and not about the derived type. I’m going to explain how you can use templates to get around this. Here’s how.
You first need to make your base class a template. This means that you can no longer use the base class as-is. You must now always make use of your base class in relation to some other type. When you declare that your derived class inherits from the base class, you provide the derived class itself as the type needed by the template base class. This looks a bit strange but it gives the base class template the information it needs to know exactly what derived class is using it. When the base class wants to call a method that only exists in the derived class, it can then cast itself to the derived type and call the method. You’ll probably want to also listen to episodes 33 and 34 about casting to understand what I mean. Casting is a way to tell the compiler to treat one thing like another and now that the base class knows what type is being used to extend it, it can turn itself into that derived type and call the method.