When you think of the word algorithm what comes to your mind? Most people think they are something super complex like high frequency stock trading, Google’s Page Rank, or Facebook relevance algorithm.
These algorithms are all very complex and have taken years to create and tune, but the definition of algorithm might surprise you: The definition of algorithm is the following:
Algorithm – a step-by-step procedure for solving a problem or accomplishing some end.
Millions of Algorithms
We all follow algorithms everyday, our lives are a composite of millions of algorithms. My typical morning algorithm involves the following step-by-step procedure:
- Wake up
- Workout
- Eat Breakfast
- Drive to work
Sometimes my morning algorithm needs to change. If I am late for work I usually follow my late morning algorithm which looks something more like this:
- Wake up
Workout- Quick Breakfast
- Drive to work
Just like humans computers sometimes need to be able to adapt their algorithms on the fly. One of the best ways to encapsulate these changes in behavior is using the Template Method Design Pattern.
Template Method to the Rescue
If I were to create my morning routine in some ruby code it would look like this
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MorningAlgorithm | |
# This method is used to encapsulate the algorithm's general process. | |
# Notice this method is not concerned how the methods are accomplished | |
def execute | |
wake_up | |
workout | |
eat_breakfast | |
drive_to_work | |
end | |
def wake_up | |
puts "Get up you lazy bum" | |
end | |
def workout | |
puts "1, 2, 3… That should work" | |
end | |
def eat_breakfast | |
puts "Mmm mmm tasty" | |
end | |
def drive_to_work | |
puts "Good morning crazy drivers!" | |
end | |
end | |
morning = MorningAlgorithm.new() | |
morning.execute |
The high level steps are encapsulated in the execute method which handles the flow of the algorithm without knowing anything about the implementation of the eat_breakfast or drive_to_work.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This gist is a continuation of a previous gist which defines the MorningAlgorithm class | |
# https://gist.github.com/jpotts18/1f4269c9e1f22c963a0d | |
class LateMorningAlgorith < MorningAlgorithm | |
def work_out | |
puts "Nope…" | |
end | |
def eat_breakfast | |
puts "Grab banana and go!" | |
end | |
end | |
late_morning = LateMorningAlgorithm.new | |
late_morning.execute | |
# The LateMorningAlgorithm.execute template method will call the following methods from the following classes | |
# wake_up – MorningAlgorithm | |
# work_out – LateMorningAlgorithm | |
# eat_breakfast – LateMorningAlgorithm | |
# drive_to_work – MorningAlgorithm |
The templates method’s responsibility is to enforce behavior not implementation. Now lets take a look at what the late morning algorithm looks like.
- MorningAlgorithm#wake_up
- LateMorningAlgorithm#workout
- LateMorningAlgorithm#eat_breakfast
- MorningAlgorithm#drive_to_work
This is where the power lies! By using the template method you can encapsulate a lot of your base logic into a class and choose to override methods however you would like.
Real World Application
Let’s say that we need to gather a bunch of data over HTTP from two different datasources. One is an HTML table on a website and the other is a JSON API. The data sources will be different but the primary process is the same:
- Create a folder to store the data
- Download data and put it in the folder as raw text
- Read the data from the folder and parse data
- Write the parsed data to a CSV
If you didn’t understanding theTemplate Method you would simply start hacking together two completely unusable scrapers, but because you now know better now you would structure the classes something like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WebScraper | |
def execute | |
create_folders | |
download_data | |
parse_data | |
write_output | |
end | |
def create_folder | |
# Make directory | |
end | |
def download_data | |
# Initialize Http client | |
end | |
def parse_data | |
# Find all rows in table and put them in a hash | |
end | |
def write_output | |
# Write hash to a CSV on filesystem | |
end | |
end | |
class HTMLWebScraper < WebScraper | |
def parse_data | |
# customize how to extract the data into a hash and | |
# let the superclass take care of the rest 🙂 | |
end | |
end | |
class JSONWebScraper < WebScraper | |
def download_data | |
# initialize JSON client | |
# save data to filesystem | |
end | |
def parse_data | |
# read from file system | |
# custom JSON parsing code | |
# store results in hash | |
# let the super class take care of the rest 🙂 | |
end | |
end | |
html_scraper = HTMLWebScraper.new | |
html_scraper.execute | |
json_scraper = JSONWebScraper.new | |
json_scraper.excute |
Now that you know about the template method pattern where have you seen it before? What are some cases where it isn’t good to use the template method?