Design Patterns in Ruby — Template Method

Rachid Calazans
4 min readSep 30, 2018

--

If you prefer to read this post in Portuguese (Brazil), please click here.

In this article, we need to follow the following topics:

  • How to Make Coffee Drinks
  • Develop solution
  • Refactoring the initial solution
  • Design Pattern Template Method
  • Important points of implementations
  • Conclusion

How to Make Coffee Drinks

Cappuccino Recipe:

1- Boil some water
2- Mix the coffee, milk and chocolate powder in the boiling water
3- Serve the cappuccino in the cup
4- Add some sugar

Tea Recipe:

1- Boil some water
2- Put the infused tea in the boiling water
3- Pour the tea into the cup
4- Add lemon

Develop solution

We will implement the algorithms described above as follows:

We note that the steps are very similar between the preparations of Cappuccino and Tea.

Similar Steps:
- Boil some water
- Pour in cup

In code we can start the following change to take advantage of this similarity:

In this case we create a Abstract class of behavior, CaffeineBeverage, which has an abstract method (:prepare_recipe) and the two methods with similar algorithms that are already implemented :boilwater and :pour_in_cup.

Separate in small methods the other steps, each in its respective beverage.

When we want any of the caffeinated beverages, we can perform as follows:

Each of the drinks knows how to proceed with their algorithm, knows how to perform the sequence of steps to prepare the drink correctly.

Very good, so when we want to add any other caffeinated drink we just need to create a new Class that inherits from CaffeineBeverage and modify only what it takes, just like we did with Cappuccino and o Tea.

Let’s reflect a bit more now. Do we really need to override the method :prepare_recipe for each new type of coffee? Always need to mount the sequence of for each one?

Refactoring the initial solution

Let’s try this. Use CaffeineBeverage as the main representative of algorithm executions, defining the skeleton of any caffeinated beverage.

We’ve added two new methods, :brew_condiments and :add_aditional_condiments. They will be the extra part of each different behavior for each type of drink. Let’s modify our drinks.

What has changed here is that instead of having to override the :prepare_recipe method and call it private methods to add condiments or mix ingredients, we are just overwriting the abstract methods of CaffeineBeverage which are the methods which are part of the execution skeleton of caffeinated beverages.

For each drink we are adding the processes we want to the right methods (abstract) without having to modify the overall execution sequence of the caffeinated beverage preparation algorithm. The algorithm (steps) inserted in CaffeineBeverage is intact, with no changes.

To create other types of drinks is much simpler than the initial version, but why?

Well, because in this new version we only need to implement the two methods that are part of the main algorithm.

We do not need to make any further changes in the class CaffeineBeverage.

What we just did here was a refactoring to use the Template Methot pattern.

Design Pattern Template Method

”Defines the skeleton of an algorithm in an operation, transferring a few steps to the subclasses. In the Template Method, subclasses can redefine certain steps of an algorithm without modifying its structure.”

Therefore, the Template Method defines the steps of an algorithm and allows the implementation of one or more of these steps to be provided by subclasses.

Important points of implementations

Without Template Method:

  • Cappuccino and Tea dominate the delivery of what happens, because they control the algorithm
  • Duplication of code between subclasses
  • Any change in the algorithm code requires the opening of subclasses and the introduction of multiple changes
  • The way the classes are structured hampers the inclusion of a new caffeinated beverage

With Template Method:

  • The CaffeineBeverage class controls the delivery of what happens, it owns the algorithm and protects it
  • The CaffeineBeverage class maximizes reuse between different subclasses
  • The algorithm resides in a single place and changes only need to be made there
  • Information about the algorithm and how it is implemented is dispersed across many classes
  • The CaffeineBeverage class concentrates all the knowledge about the algorithm, depending on the subclasses only for the provision of the detailed implementations

Conclusion

The Template Method Pattern allows us to keep our code cleaner and reusable with principles of SOLID and DRY, without losing control of our algotithms.

It is very good when we need to add something new or adjust the algorithm because we will need to add or change only a small piece of code.

Thank you!

Here is a link from other post my about Design Pattern very interesting and even with some similar behaviors, the Strategy.

--

--

Rachid Calazans

💻 Remote Software Engineer at Tidy, 9+xp, 🎙 Podcaster, 📖 Autor, 🙏 Evangelist of TDD and BDD Methodologies linktr.ee/rachidcalazans