A logbook for curious waters
← Software Engineering Field Guide

Form Template Method

Before you begin: Inheritance, overriding, and ordered method calls.

Form Template Method reorganizes similar algorithms so their common sequence lives in one base method while differing steps are supplied by subclasses. The resulting structure is the Template Method pattern; this refactoring describes how to get there from duplicated algorithms. 1

Original version: two reports repeat the same sequence

Both reports trim a title, format it, and append an end marker. Only the title decoration differs. The examples assume a non-null string.

public sealed class PlainReport
{
    public string Render(string title)
    {
        string clean = title.Trim();
        return clean + "\nEND";
    }
}
public sealed class BracketReport
{
    public string Render(string title)
    {
        string clean = title.Trim();
        return "[" + clean + "]\nEND";
    }
}
class PlainReport:
    def render(self, title):
        clean = title.strip()
        return clean + "\nEND"


class BracketReport:
    def render(self, title):
        clean = title.strip()
        return "[" + clean + "]\nEND"

If normalization or the end marker changes, both algorithms must stay aligned.

Refactored version: one sequence, one replaceable step

public abstract class Report
{
    public string Render(string title)
    {
        string clean = title.Trim();
        return Decorate(clean) + "\nEND";
    }
    protected abstract string Decorate(string title);
}
public sealed class PlainReport : Report
{
    protected override string Decorate(string title) { return title; }
}
public sealed class BracketReport : Report
{
    protected override string Decorate(string title) { return "[" + title + "]"; }
}

Render fixes the order: trim, decorate, append. Subclasses only supply Decorate. The nonvirtual public method is not itself an override point in this C# design.

class Report:
    def render(self, title):
        clean = title.strip()
        return self._decorate(clean) + "\nEND"

    def _decorate(self, title):
        raise NotImplementedError


class PlainReport(Report):
    def _decorate(self, title):
        return title


class BracketReport(Report):
    def _decorate(self, title):
        return "[" + title + "]"

Subclasses inherit render and provide _decorate. Python still allows a subclass to override render; the intended extension contract is a design convention unless additional tooling enforces it.

Extract the real shared algorithm

The common steps must occur in the same meaningful order. Do not force two merely similar workflows into a base class full of flags and empty hook methods.

Here the texts before and after are identical, including the newline. In a larger operation, tests should also observe exceptions and side effects around the varying steps.

For one small variation, passing a formatting function may be simpler and more flexible than inheritance. Template Method is useful when the stable sequence itself is an important reusable contract and the allowed variation can be expressed through a few understandable steps.

Sources

  1. Martin Fowler — Form Template Method.