assignmentTemplate Method
Template Method is a behavioral design pattern that allows you to define a common abstract scaffold of a base class that can then be overwritten by subclasses.
Let’s assume that our application has an example table with user data.
| ID | NAME | EMAIL |
|----|-----------|--------------------|
| 1 | John Doe | john.doe@email.com |
|----|-----------|--------------------|
| 2 | Jane Doe | jane.doe@email.com |
We want to add functionality to it that will allow us to export it to files of various formats, e.g. HTML and JSON.
So let’s create pseudo code that will allow us to do this step by step:
Having written pseudo code, we can create a parent class that will perform the appropriate steps.
class Export
attr_reader :data, :file
# Raw data pass as an argument
def initialize(data)
@data = data
end
# Abstract steps, without implementation
def call
create_file
format_data
add_data_to_file
save
end
private
def create_file
raise 'Called abstract method: create_file'
end
def format_data
raise 'Called abstract method: format_data'
end
def add_data_to_file
raise 'Called abstract method: add_data_to_file'
end
def save
raise 'Called abstract method: save'
end
# Common method that can be used by subclasses
def timestamps
Time.new.to_i
end
end
As seen above, we have defined the specific steps that must be performed to export a file to various formats. Each of these methods should be overridden by the child class to avoid causing an error. The exception here is the timestamp method, which can be used universally by all classes.
So it’s time to create class that include proper implementation for JSON format:
require 'json'
class JsonExport < Export
def create_file
@file = File.new("./users_#{timestamps}.json", "w")
end
def format_data
@data = JSON.parse(data)
end
def add_data_to_file
file.write = data
end
def save
file.close
end
end
And do the same for HTML:
class HtmlExport < Export
def create_file
@file = File.new("./users_#{timestamps}.html", "w")
end
def format_data
# In this case we don't want to format data yet, however
# we must override this method to avoid error
end
def add_data_to_file
file.write << '<table>'
data.map do |user|
file.write << '<tr>'
# Rest of the implementation that adds users data and
# creates html table
file.write << '</tr>'
end
file.write << '</table>'
end
def save
file.close
end
end
Now if we prepare data from the table and run our code, we can easily generate code in both JSON and HTML formats.
users = [
{ id: 1, name: 'John Doe', email: 'john.doe@email.com' },
{ id: 2, name: 'Jane Doe', email: 'jane.doe@email.com' }
]
JsonExport.call(users) # => Generate JSON file
HtmlExport.call(users) # => Generate HTML file
So, as you can see, the Template Method allows us to implement abstract code, and then its inheriting classes will be responsible for a specific implementation. In the parent class we can also add common code that will be used by all implementations like timestamps in this example.
There is also nothing stopping us from creating more implementations in the future, including other formats. e.g. TXT or CSV.