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)