DEV Community

Luiz Cezer
Luiz Cezer

Posted on • Edited on

Design Patterns in Ruby: Template Method pattern

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.

References

Top comments (0)