Template Method Design Pattern in Ruby

1. Definition

The Template Method Design Pattern defines the program skeleton in an algorithm in a method of an abstract class but delays some steps to subclasses. This allows subclasses to redefine certain steps of an algorithm without changing the algorithm's structure.

2. Problem Statement

When implementing an algorithm, some parts remain consistent while others can vary. Hardcoding all variants of these dynamic parts directly into the algorithm makes the code redundant, less modular, and harder to maintain.

3. Solution

Separate the invariant (unchanging) parts of the algorithm into a 'template method' within an abstract base class. Allow the variant parts to be implemented by subclasses of this base class. This ensures that the overall algorithm structure remains consistent, while specific steps can be uniquely tailored by the subclasses.

4. Real-World Use Cases

1. Different recipes have a common procedure but varying ingredients or cooking techniques.

2. A software build process where steps like code compilation are constant, but pre-build or post-build steps might vary.

3. Document generation systems where the structure is consistent but content or format might change.

5. Implementation Steps

1. Identify the parts of the algorithm that remain constant and those that vary.

2. Create an abstract class with the template method defining the skeleton of the algorithm.

3. Let the variable steps be handled by abstract methods in the base class.

4. Create concrete subclasses that implement these abstract methods.

6. Implementation in Ruby

# Step 1 & 2: Abstract Class and Template Method
class AbstractRecipe
  # Template method
  def make
    prepare_ingredients
    cook
    finalize_dish
  end
  def prepare_ingredients
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
  def cook
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
  def finalize_dish
    puts "Dish is ready to be served!"
  end
end
# Step 4: Concrete Subclasses
class PastaRecipe < AbstractRecipe
  def prepare_ingredients
    puts "Preparing pasta and sauce."
  end
  def cook
    puts "Boiling pasta and cooking sauce."
  end
end
class SaladRecipe < AbstractRecipe
  def prepare_ingredients
    puts "Chopping vegetables."
  end
  def cook
    puts "Mixing vegetables with dressing."
  end
end
# Client Code
pasta = PastaRecipe.new
pasta.make
salad = SaladRecipe.new
salad.make

Output:

Preparing pasta and sauce.
Boiling pasta and cooking sauce.
Dish is ready to be served!
Chopping vegetables.
Mixing vegetables with dressing.
Dish is ready to be served!

Explanation:

1. AbstractRecipe defines the template method make that outlines the structure of the recipe algorithm.

2. The steps that vary across recipes, prepare_ingredients, and cook, are defined as abstract methods.

3. Concrete classes like PastaRecipe and SaladRecipe provide specific implementations for these steps, tailoring them to their unique requirements.

4. The template method ensures that while individual steps might vary, the overarching structure of the algorithm remains consistent.

7. When to use?

Use the Template Method Pattern when:

1. You have a multi-step algorithm where most of the steps remain consistent, but a few vary based on the context.

2. You want to avoid redundancy and enhance code modularity by isolating the variable steps from the invariant ones.

3. You want to provide a clear structure for algorithms, with a defined order of steps.


Comments