Skip to main content

Pattern to pattern: Template Method & Strategy

·4 mins

Recently I wrote about the Template Method pattern and how it’s implemented in Ruby. In the comments, one of the readers commented that the Template Method pattern is in fact the Strategy pattern. After thinking hard about how I should answer the question, I thought about writing a post comparing the two patterns. So, here it is - my version of design patterns head to head. Let’s see what these two patterns have in common and what are their key differences.

Template Method pattern #

The most important thing to remember about this pattern is: boilerplate code goes in the parent class while the algorithm-specific methods are implemented (usually overridden) in the child classes. This means, that all of the child classes will share the functionality of the parent class (inheritance, duh!), but the parent class will only be a skeletal class, i.e. one cannot create objects out of it. On the other hand, the child classes will only override the methods that are specific to their domain. You can read more about this in my recent article on Template Method pattern.

Strategy Pattern #

In it’s core the Strategy Pattern (or SP) is about encapsulating logic into objects, making them interchangeable and using those objects as part of an algorithm. This means that an algorithm (context) can have it’s behaviour changed in runtime by an object (strategy).

Implementing the Strategy pattern #

Let’s see a short example of how we can use the Strategy pattern. Let’s create a simple Invoice class.

class Invoice
  attr_accessor :formatter

  def initialize amount, buyer, seller
    @amount = amount
    @buyer = buyer
    @seller = seller
    @formatter = JSONFormatter.new
  end

  def generate
    @formatter.format! @amount, @buyer, @seller
  end

end

As you can see, the Invoice is consisted of an amount, the name of the buyer and the name of the seller.  In it’s constructor, a formatter of the Invoice is created. The formatter is an object of a class that has a method format! which takes the buyer, seller and amount as params. When the method is called, it will create the invoice in it’s specific format. One very important aspect of the strategy classes is that the context class expects the strategy classes to implement, in our example,** a format! method**. For example, in Java this is achieved by using interfaces, which force a class to implement certain methods. But because Ruby is a dynamic language, there’s no such thing as an interface and we must think about this aspect in advance. That being said, lets take a look at the formatter classes - they’re all pretty simple.

class JSONFormatter
  def format! amount, buyer_name, seller_name
    %Q{
      {
        "buyer" => "#{buyer_name}",
        "seller" => "#{seller_name}",
        "amount" => "#{amount}"
      }
    }
  end
end

The JSONFormatter creates the invoice in JSON format. As a side note, I am using the percentage string notation because it’s a bit more readable this way.

class XMLFormatter
  def format! amount, buyer_name, seller_name
    %Q{
     <invoice>
       <buyer>#{buyer_name}</buyer>
       <seller>#{seller_name}</seller>
       <amount>#{amount}</amount>
     </invoice>
   }
  end
end

The XMLFormatter creates the invoice in XML format.

class YAMLFormatter
  def format! amount, buyer_name, seller_name
    %Q{
      ---
      invoice:
        buyer: #{buyer_name}
        seller: #{seller_name}
        amount: #{amount}
    }
  end
end

And, last but not least, YAMLFormatter creates the invoice in YAML format. The beauty of the Strategy Pattern lies in the context (the Invoice) and the strategies (the formatters). You see, when we first create the Invoice, we can use it to print out a JSON formatted invoice. And it’s cool. But the cooler thing is that you can change how the Invoice will behave in runtime, meaning, you can change the formatter object and the behaviour of the invoice will change. Or, said in a more abstract way, the context’s behaviour can change with every different strategy you apply to the context. So, how this applies to our code?

invoice = Invoice.new 100, "John", "Jane"
puts invoice.generate

The first time we generate the Invoice, we use the JSONFormatter and of course we get an invoice back in a JSON format.

{
  "buyer" => "John",
  "cashier" => "Jane",
  "amount" => "100"
}

Now, if we change the formatter to that same Invoice object

invoice.formatter = XMLFormatter.new
puts invoice.generate

…we will get the same invoice, formatted in XML.

<invoice>
  <buyer>John</buyer>
  <cashier>Jane</cashier>
  <amount>100</amount>
</invoice>

You see, our formatters change the behaviour of our Invoice.

Strategy and Template Method #

So what are the similarities and what are the key differences in these two design patterns? Well, it might be obvious to some of you, confusing to others (as it was for me at the beginning). Both patterns are about encapsulating domain-specific algorithms into objects. But, the key difference is that Strategy Pattern is about modifying a behaviour of a context in runtime using strategies, while Template Method Pattern is about following a skeleton implementation of an algorithm and modifying its behaviour by overriding methods of the skeleton class in the subclasses.