design pattern

Behavioral Design Patterns: Template Method

Today we’ll take a look at the template method design pattern, which is the final design pattern introduced in the well-known book 1994, Design Patterns: Elements of Reusable Object-Oriented Software. We’ve covered all other patterns thus far in our detailed Guide to Software Design Patterns series, with both real world and fully functional C# code samples of each, illustrating how the patterns can be used and implemented in your own code.

The template method design pattern is intended to outline the basic structure or “skeleton” of an algorithm, without explicitly defining (or advertising) the logic of each step within the overall structure to the client. This pattern is ideal for complex algorithms that must be shared and executed by multiple classes, where each class must define their own specific implementation.

Let’s get to exploring the template method pattern with both a real world example, as well as a functional C# sample!

In the Real World

In terms of components, the template method design pattern is one of the simplest patterns we’ve examined, as it includes only two parts:

  • AbstractClass – Defines a series of primitive operations, many of which inheriting ConcreteClasses must implement. These operations are executed within the TemplateMethod, which is the primary method of the AbstractClass that is invoked by each instance of the ConcreteClass. This TemplateMethod performs all the necessary operations (primitive operations) that makeup the main algorithm.
  • ConcreteClass – Each ConcreteClass implements all the primitive operation methods that were declared in the AbstractClass. When the client creates a new ConcreteClass instance, the TemplateMethod is invoked, which executes all primitive operations specific to this ConcreteClass implementation.

Since the entire purpose of the template method is to define a TemplateMethod that invokes a particular algorithm (i.e. a series of method calls), this pattern is frequently used in the real world, where a step-by-step process is required to complete a complex task. For example, let’s consider what might be required to get a new TV show up and running on a broadcast network or streaming service. I’m no expert, but from a layman’s perspective we might assume that broadcasting a new show requires these steps, in roughly the following order:

  1. Write a script.
  2. Pitch the script to a network.
  3. Cast some actors.
  4. Shoot the pilot.
  5. Determine the best broadcast time slot.
  6. Broadcast!

Now, undoubtedly some of these steps can occur at different points in the process, but, generally speaking, most of the time pitching will occur after a script as written, as will casting actors. Certainly, the pilot episode cannot be shot if there are no actors nor a network to help with production.

Given that the process of creating and broadcasting a show is more or less an ordered “algorithm”, it’s a perfect example of the template method design pattern in real life. The above steps are fairly generic and ordered, but the exact implementation of them will vary, depending on factors like the type of show, the network involved, how it is broadcast, and so forth. Thus, each particular network acts as a unique ConcreteClass, implementing all the primitive operation steps to produce and broadcast a show that we see above, but doing so in their own way.

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

How It Works In Code

Our sample code continues with the television show example. Specifically, we want to be able to broadcast a Show (AbstractClass), but doing so will depend on the particular NetworkShow (ConcreteClass) that inherits from Show. The Show class has a single Broadcast() method, which acts as the TemplateMethod that invokes all the various primitive operations required to actually get the show created and broadcast.

Thus, we begin with the Show (AbstractClass):

As mentioned, the Broadcast() method is the TemplateMethod that will be invoked by all object instances, so we see that it invokes a series of methods to accomplish this — everything from WriteScript() to AssignBroadcastSlot(). Once complete, it outputs a confirmation with formatted details of the Show that is being Broadcast().

It’s also worth noting that a few #regions are defined, just to illustrate the different method types we can use. For this example, we’ve only chosen to explicitly implement the AssignBroadcastSlot() and FindNetwork() methods within all subclasses, so setting these to abstract will force this behavior. Meanwhile, any methods we want to allow a default behavior for — such as CastActors(), ShootPilot(), and WriteScript() — are virtual methods, so they have their own base logic, which can be overriden if necessary.

To help handle the day of the week and time slot requirements for Shows that may need it, we’ve also created the helper BroadcastSlot class:

The comments outline most of the functionality here, but the basic purpose is to allow each Show instance to specify whether it’s broadcast at a particular time on a specific day of the week, like most network shows, or whether it’s always available on a streaming service (such as YouTube or Netflix). As we’ll see in a moment, a new instance of BroadcastSlot is created within each NetworkShow (ConcreteClass) implementation’s AssignBroadcastSlot() method, and then assigned to the Show.BroadcastSlot property.

Speaking of ConcreteClasses, now let’s take a look at the three different NetworkShow implementations we’ve defined for this example, covering the networks of NBC, Netflix, and YouTube:

As previously discussed, we’ve chosen to only require that two of our primitive operation methods be overriden, AssignBroadcastSlot() and FindNetwork(), since these operations will significantly change depending if the show is on a regular broadcast network or on an online streaming service.

Of particular note is the NBCShow(string name, DayOfWeek day, int hour, int minute = 0) constructor method, which forces the client to specify a broadcast day and time slot when creating a new NBCShow. On the other hand, the YouTubeShow(string name) and NetflixShow(string name) constructor methods only require the Show.Name property to be specified, since the BroadcastSlot for both streaming services has a Type property set to SlotType.Streaming. This ensures that the Show has no specific day of the week or time slot for broadcast, since such shows can be watched anytime. Other than that, the FindNetwork() method just assigns the Show.Network property.

Obviously, further refinement of this example might include refactoring the current default methods like CastActors(), but the above should properly illustrate the purpose and setup of the template method design pattern.

Now, to test all this out with client code we’re creating just a handful of shows, one for each NetworkShow (ConcreteClass) implementation:

We start with The Office, which was on NBC and (mostly) aired on Thursdays at 9PM. As we saw above, the NBCShow class requires that a day of the week, hour, and optional minute be specified in its constructor, so that’s where we pass the data indicating when the show will broadcast. Once a new instance is created, we simply call theOffice.Broadcast(), which is the main TemplateMethod of all Shows. This invokes all underlying primitive operations and gets our show on the air! The output this produces can be seen below:

As intended, we see an output message for each primitive operation method that was invoked by Broadcast(), along with a final message from Broadcast() itself that summarizes the show, the network, and when it broadcasts.

We’re also creating and broadcasting Computerphile on YouTube, and Stranger Things on Netflix. Both of these networks are streaming services, so we don’t need to specify a time slot. This is confirmed with the output from executing both of these show creations:

There we have it! Hopefully this article provided a bit of insight into the purpose and implementation of the template method design pattern. With that, our series comes to a close, but, for more information on all the other popular design patterns, head on over to our detailed design pattern series here!