By definition, the pattern defines a skeleton of an algorithm, but leave certain parts of this algorithm to be implemented by subclasses. Those subclasses can override the main behavior, without a need to change the main structure of the base algorithm.
In other words, the base class defines a skeleton and subclasses must fill this skeleton with your own implementation.
Deal with different membership plans
Let's say that you need to add a membership feature to your application, and the membership has two different plans, the basic and the premium. Each of these plans has their own title, description and a bunch of benefits.
At first try, you can simply add an if statement to check which type
plan will be created, and it seems a good idea.
class Plan
attr_reader :title, :description, :benefits
def initialize(kind)
if kind == :basic
@title = "I'm the basic plan"
@description = "My description of basic plan"
@benefits = ['It is free', 'Access to one account', 'Basic features']
else
@title = "I'm the other plan"
@description = "My description of other plan"
@benefits = ['No benefits']
end
end
def output
output = <<-STRING
Title: #{title}
Description: #{description}
Plan benefits: #{benefits.join(', ')}.
STRING
puts(output)
end
end
####
basic = Plan.new(:basic)
basic.output
"""
Title: I'm the basic plan
Description: My description of basic plan
Plan benefits: It is free, Access to one account, Basic features.
"""
other_plan = Plan.new(:other)
other_plan.output
"""
Title: I'm the other plan
Description: My description of other plan
Plan benefits: No benefits.
"""
But, what will happen if we need to add a check for a new plan called premium
? If we keep in this approach, the code will look like this:
class Plan
attr_reader :title, :description, :benefits
def initialize(kind)
if kind != :basic
@title = "I'm the basic plan"
@description = "My description of basic plan"
@benefits = ['It is free', 'Access to one account', 'Basic features']
elsif kind == :premium
@title = "I'm the premium plan"
@description = "My description of premium plan"
@benefits = ['It is paid', 'Access to ten accounts', 'Premium features', 'Access to support']
else
@title = "I'm the other plan"
@description = "My description of other plan"
@benefits = ['No benefits']
end
end
# ...
end
And what if we need to add a new plan called master premium
? Yeah, this approach will not scale well and will deny the code to be flexible and with support many plans.
Using Template Method Pattern to allow multiple plans
As I said before, the main definition of Template Method
pattern is to define a skeleton and let the subclasses to fill this skeleton with their own implementation.
So let's define the base class:
class Base
def title
raise 'Must implement'
end
def description
raise 'Must implement'
end
def benefits
raise 'Must implement'
end
def output
output = <<-STRING
Title: #{title}
Description: #{description}
Plan benefits: #{benefits}.
STRING
puts(output)
end
end
It's pretty basic, the Base
class just define 3 methods title
, description
and benefits
. The output
method, contains the skeleton algorithm with the behaviors that subclasses will implement.
The importance of Base
class is to define an interface that all subclasses must follow and implement.
Now let's create the subclasses:
class BasicPlan < Base
def title
"I'm the basic plan"
end
def description
"My description of basic plan"
end
def benefits
['It is free', 'Access to one account', 'Basic features'].join(', ')
end
end
###
class PremiumPlan < Base
def title
"I'm the premium plan"
end
def description
"My description of premium plan"
end
def benefits
[
'It will cost USD 10.00',
'Access to ten accounts',
'Premium features',
'You will receive a gift on your birthday'
].join(', ')
end
end
Each subclass implement your own behavior for each method without worrying about output
method, your only
a concern is to implement the hook methods, that will be used inside Base#output
.
And what happens if we need to add a new membership plan? Well, it very simple, we just need to create the new class and implement Base
class methods.
class AwesomePlan < Base
def title
"I'm the awesome plan"
end
def description
"My description of awesome plan"
end
def benefits
[
'It will cost USD 1,000.00',
'Access to a hundread accounts',
'Awesome features',
'You will receive a gift on your birthday',
].join(', ')
end
end
###
"""
Title: I'm the awesome plan
Description: My description of awesome plan
Plan benefits: It will cost USD 1,000.00, Access to a hundread accounts, Awesome features, You will receive a gift on your birthday.
"""
Well, this is it, this is how to use the Template Method pattern with Ruby.
Top comments (0)