Chapter 8. The Template Method Pattern: Encapsulating Algorithms

image with no caption

We’re on an encapsulation roll; we’ve encapsulated object creation, method invocation, complex interfaces, ducks, pizzas...what could be next? We’re going to get down to encapsulating pieces of algorithms so that subclasses can hook themselves right into a computation anytime they want. We’re even going to learn about a design principle inspired by Hollywood.

It’s time for some more caffeine

Some people can’t live without their coffee; some people can’t live without their tea. The common ingredient? Caffeine, of course!

But there’s more; tea and coffee are made in very similar ways. Let’s check it out:

image with no caption

Whipping up some coffee and tea classes (in Java)

Let’s play “coding barista” and write some code for creating coffee and tea.

image with no caption

Here’s the coffee:

image with no caption

And now the Tea...

image with no caption
image with no caption
image with no caption

Sir, may I abstract your Coffee, Tea?

It looks like we’ve got a pretty straightforward design exercise on our hands with the Coffee and Tea classes. Your first cut might have looked something like this:

image with no caption

Brain Power

Did we do a good job on the redesign? Hmmmm, take another look. Are we overlooking some other commonality? What are other ways that Coffee and Tea are similar?

Taking the design further...

So what else do Coffee and Tea have in common? Let’s start with the recipes.

image with no caption

Notice that both recipes follow the same algorithm:

  • ① Boil some water.

    Note

    These two are already abstracted into the base class.

  • ② Use the hot water to extract the coffee or tea.

    Note

    These aren’t abstracted but are the same; they just apply to different beverages.

  • ③ Pour the resulting beverage into a cup.

  • ④ Add the appropriate condiments to the beverage.

So, can we find a way to abstract prepareRecipe() too? Yes, let’s find out...

Abstracting prepareRecipe()

Let’s step through abstracting prepareRecipe() from each subclass (that is, the Coffee and Tea classes)...

  • ① The first problem we have is that Coffee uses brewCoffeeGrinds() and addSugarAndMilk() methods, while Tea uses steepTeaBag() and addLemon() methods.

    image with no caption

    Let’s think through this: steeping and brewing aren’t so different; they’re pretty analogous. So let’s make a new method name, say, brew(), and we’ll use the same name whether we’re brewing coffee or steeping tea.

    Likewise, adding sugar and milk is pretty much the same as adding a lemon: both are adding condiments to the beverage. Let’s also make up a new method name, addCondiments(), to handle this. So, our new prepareRecipe() method will look like this:

    void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
  • ② Now we have a new prepareRecipe() method, but we need to fit it into the code. To do this we are going to start with the CaffeineBeverage superclass:

    image with no caption
  • ③ Finally, we need to deal with the Coffee and Tea classes. They now rely on CaffeineBeverage to handle the recipe, so they just need to handle brewing and condiments:

    image with no caption

What have we done?

image with no caption

Meet the Template Method

We’ve basically just implemented the Template Method Pattern. What’s that? Let’s look at the structure of the CaffeineBeverage class; it contains the actual “template method”:

image with no caption

The Template Method defines the steps of an algorithm and allows subclasses to provide the implementation for one or more steps.

Let’s make some tea...

image with no caption

Behind the Scenes

Let’s step through making a tea and trace through how the template method works. You’ll see that the template method controls the algorithm; at certain points in the algorithm, it lets the subclass supply the implementation of the steps...

  • ① Okay, first we need a Tea object...

    Tea myTea = new Tea();
  • ② Then we call the template method:

    image with no caption

    which follows the algorithm for making caffeine beverages...

  • ③ First we boil water:

    image with no caption

    which happens in CaffeineBeverage.

  • ④ Next we need to brew the tea, which only the subclass knows how to do:

    brew();
  • ⑤ Now we pour the tea in the cup; this is the same for all beverages so it happens in CaffeineBeverage:

    pourInCup();
  • ⑥ Finally, we add the condiments, which are specific to each beverage, so the subclass implements this:

    addCondiments();

What did the Template Method get us?

Underpowered Tea & Coffee implementation

New, hip CaffeineBeverage powered by Template Method

Coffee and Tea are running the show; they control the algorithm.

The CaffeineBeverage class runs the show; it has the algorithm, and protects it.

Code is duplicated across Coffee and Tea.

The CaffeineBeverage class maximizes reuse among the subclasses.

Code changes to the algorithm require opening the subclasses and making multiple changes.

The algorithm lives in one place and code changes only need to be made there.

Classes are organized in a structure that requires a lot of work to add a new caffeine beverage.

The Template Method version provides a framework that other caffeine beverages can be plugged into. New caffeine beverages only need to implement a couple of methods.

Knowledge of the algorithm and how to implement it is distributed over many classes.

The CaffeineBeverage class concentrates knowledge about the algorithm and relies on subclasses to provide complete implementations.

Template Method Pattern defined

You’ve seen how the Template Method Pattern works in our Tea and Coffee example; now, check out the official definition and nail down all the details:

Note

The Template Method Pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

This pattern is all about creating a template for an algorithm. What’s a template? As you’ve seen it’s just a method; more specifically, it’s a method that defines an algorithm as a set of steps. One or more of these steps is defined to be abstract and implemented by a subclass. This ensures the algorithm’s structure stays unchanged, while subclasses provide some part of the implementation.

Let’s check out the class diagram:

image with no caption

Hooked on Template Method...

A hook is a method that is declared in the abstract class, but only given an empty or default implementation. This gives subclasses the ability to “hook into” the algorithm at various points, if they wish; a subclass is also free to ignore the hook.

image with no caption

There are several uses of hooks; let’s take a look at one now. We’ll talk about a few other uses later:

image with no caption

Using the hook

To use the hook, we override it in our subclass. Here, the hook controls whether the CaffeineBeverage evaluates a certain part of the algorithm; that is, whether it adds a condiment to the beverage.

How do we know whether the customer wants the condiment? Just ask!

image with no caption

Let’s run the Test Drive

Okay, the water’s boiling... Here’s the test code where we create a hot tea and a hot coffee.

image with no caption

And let’s give it a run...

image with no caption
image with no caption

You know what? We agree with you. But you have to admit before you thought of that, it was a pretty cool example of how a hook can be used to conditionally control the flow of the algorithm in the abstract class. Right?

We’re sure you can think of many other more realistic scenarios where you could use the template method and hooks in your own code.

The Hollywood Principle

We’ve got another design principle for you; it’s called the Hollywood Principle:

image with no caption

Note

The Hollywood Principle

Don’t call us, we’ll call you.

Easy to remember, right? But what has it got to do with OO design?

The Hollywood Principle gives us a way to prevent “dependency rot.” Dependency rot happens when you have high-level components depending on low-level components depending on high-level components depending on sideways components depending on low-level components, and so on. When rot sets in, no one can easily understand the way a system is designed.

With the Hollywood Principle, we allow low-level components to hook themselves into a system, but the high-level components determine when they are needed, and how. In other words, the high-level components give the low-level components a “don’t call us, we’ll call you” treatment.

image with no caption

The Hollywood Principle and Template Method

The connection between the Hollywood Principle and the Template Method Pattern is probably somewhat apparent: when we design with the Template Method Pattern, we’re telling subclasses, “don’t call us, we’ll call you.” How? Let’s take another look at our CaffeineBeverage design:

image with no caption

Brain Power

What other patterns make use of the Hollywood Principle?

The Factory Method, Observer; any others?

Template Methods in the Wild

The Template Method Pattern is a very common pattern and you’re going to find lots of it in the wild. You’ve got to have a keen eye, though, because there are many implementations of the template methods that don’t quite look like the textbook design of the pattern.

This pattern shows up so often because it’s a great design tool for creating frameworks, where the framework controls how something gets done, but leaves you (the person using the framework) to specify your own details about what is actually happening at each step of the framework’s algorithm.

Let’s take a little safari through a few uses in the wild (well, okay, in the Java API)...

image with no caption

Sorting with Template Method

What’s something we often need to do with arrays? Sort them!

image with no caption

Recognizing that, the designers of the Java Arrays class have provided us with a handy template method for sorting. Let’s take a look at how this method operates:

Note

We’ve pared down this code a little to make it easier to explain. If you’d like to see it all, grab the Java source code and check it out...

image with no caption

We’ve got some ducks to sort...

Let’s say you have an array of ducks that you’d like to sort. How do you do it? Well, the sort template method in Arrays gives us the algorithm, but you need to tell it how to compare ducks, which you do by implementing the compareTo() method... Make sense?

image with no caption
image with no caption

Good point. Here’s the deal: the designers of sort() wanted it to be useful across all arrays, so they had to make sort() a static method that could be used from anywhere. But that’s okay, it works almost the same as if it were in a superclass. Now, here is one more detail: because sort() really isn’t defined in our superclass, the sort() method needs to know that you’ve implemented the compareTo() method, or else you don’t have the piece needed to complete the sort algorithm.

To handle this, the designers made use of the Comparable interface. All you have to do is implement this interface, which has one method (surprise): compareTo().

What is compareTo()?

The compareTo() method compares two objects and returns whether one is less than, greater than, or equal to the other. sort() uses this as the basis of its comparison of objects in the array.

image with no caption

Comparing Ducks and Ducks

Okay, so you know that if you want to sort Ducks, you’re going to have to implement this compareTo() method; by doing that you’ll give the Arrays class what it needs to complete the algorithm and sort your ducks.

Here’s the duck implementation:

image with no caption
image with no caption

Let’s sort some Ducks

Here’s the test drive for sorting Ducks...

image with no caption

Let the sorting commence!

image with no caption

The making of the sorting duck machine

image with no caption

Behind the Scenes

  • ① First, we need an array of Ducks:

    Duck[] ducks = {new Duck("Daffy", 8), ... };
  • ② Then we call the sort() template method in the Array class and pass it our ducks:

    image with no caption

    The sort() method (and its helper mergeSort()) control the sort procedure.

  • ③ To sort an array, you need to compare two items one by one until the entire list is in sorted order.

    When it comes to comparing two ducks, the sort method relies on the Duck’s compareTo() method to know how to do this. The compareTo() method is called on the first duck and passed the duck to be compared to:

    image with no caption
  • ④ If the Ducks are not in sorted order, they’re swapped with the concrete swap() method in Arrays:

    swap()
  • ⑤ The sort() method continues comparing and swapping Ducks until the array is in the correct order!

Brain Power

We know that we should favor composition over inheritance, right? Well, the implementers of the sort() template method decided not to use inheritance and instead to implement sort() as a static method that is composed with a Comparable at runtime. How is this better? How is it worse? How would you approach this problem? Do Java arrays make this particularly tricky?

Brain2 Power

Think of another pattern that is a specialization of the template method. In this specialization, primitive operations are used to create and return objects. What pattern is this?

Swingin’ with Frames

Up next on our Template Method safari... keep your eye out for swinging JFrames!

image with no caption

If you haven’t encountered JFrame, it’s the most basic Swing container and inherits a paint() method. By default, paint() does nothing because it’s a hook! By overriding paint(), you can insert yourself into JFrame’s algorithm for displaying its area of the screen and have your own graphic output incorporated into the JFrame. Here’s an embarrassingly simple example of using a JFrame to override the paint() hook method:

image with no caption
image with no caption

Applets

Our final stop on the safari: the applet.

image with no caption

You probably know an applet is a small program that runs in a web page. Any applet must subclass Applet, and this class provides several hooks. Let’s take a look at a few of them:

image with no caption

Concrete applets make extensive use of hooks to supply their own behaviors. Because these methods are implemented as hooks, the applet isn’t required to implement them.

Tools for your Design Toolbox

We’ve added Template Method to your toolbox. With Template Method you can reuse code like a pro while keeping control of your algorithms.

image with no caption
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.236.247.213