Share This Article
The template method in Ruby is one of the most practical design patterns in object-oriented programming.
The template method allows you to define the steps of an algorithm and then will enable subclasses to provide the implementation for one or more actions.
This is useful when you want to keep the overall algorithm the same but you want to be able to change the implementation of some of the steps.
Template Method Implementation in Ruby
Here’s an example of how the template method pattern can be implemented in Ruby:
class Template
def print
before_print
print_data
after_print
end
def before_print
raise NotImplementedError
end
def print_data
raise NotImplementedError
end
def after_print
raise NotImplementedError
end
end
class PrettyPrint < Template
def before_print
puts "Started printing..."
end
def print_data
puts "Printing..."
end
def after_print
puts "Finished printing."
end
end
p = PrettyPrint.new
p.print
The Template
class defines the algorithm for printing data in the example above.
The PrettyPrint
class is a subclass that implements the before_print
, print_data
and after_print
methods.
You can see how this allows us to change the implementation of the algorithm while keeping the overall structure the same.
Another Template Method Example in Ruby
The template method can be used to implement the _iterator design pattern_, which allows you to iterate over a data collection without knowing the underlying implementation.
Here’s an example:
class Collection
def initialize(items)
@items = items
end
def each
@items.each { |item| yield item }
end
end
class ArrayCollection < Collection
def initialize(items)
super
end
end
class HashCollection < Collection
def initialize(items)
super
end
end
# array collection
array_collection = ArrayCollection.new([1,2,3])
array_collection.each { |i| puts i }
# hash collection
hash_collection = HashCollection.new({first: 1, second: 2, third: 3})
hash_collection.each { |k,v| puts "#{k} = #{v}" }
The Collection
class defines the algorithm for iterating over data collection.
The ArrayCollection
and HashCollection
classes are subclasses that implement the each
method.
You can see in this example how the algorithm is the same, but the implementation is different depending on the type of data we are iterating over.
Using the Built-In Enumerable Module
In Ruby, the enumerable module provides many methods you need to implement the template method pattern.
Here are some of the methods you can use:
- Enumerable#each
- Enumerable#collect
- Enumerable#select
- Enumerable#find
- Enumerable#inject
Here’s an example of how you can use the `Enumerable#collect` method:
array = [1,2,3,4]
result = array.collect { |i| i * 2 }
# result is [2,4,6,8]
Summary
This article taught you how to implement the template method pattern in Ruby.
You’ve also learned how to use the built-in methods from the Enumerable module to implement the template method pattern.