Design Patterns in PHP – Template method pattern

Template method pattern

The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.

The helper methods may be either abstract methods, in which case subclasses are required to provide concrete implementations, or hook methods, which have empty bodies in the superclass. Subclasses can (but are not required to) customize the operation by overriding the hook methods. The intent of the template method is to define the overall structure of the operation, while allowing subclasses to refine, or redefine, certain steps.

This pattern has two main parts:

The “template method” is implemented as a method in a base class (usually an abstract class). This method contains code for the parts of the overall algorithm that are invariant. The template ensures that the overarching algorithm is always followed. In the template method, portions of the algorithm that may vary are implemented by sending self messages that request the execution of additional helper methods. In the base class, these helper methods are given a default implementation, or none at all (that is, they may be abstract methods).

Subclasses of the base class “fill in” the empty or “variant” parts of the “template” with specific algorithms that vary from one subclass to another. It is important that subclasses do not override the template method itself.

The template method is used for the following reasons.

  • It lets subclasses implement varying behavior (through overriding of the hook methods). It avoids duplication in the code: the general workflow of the algorithm is implemented once in the abstract class’s template method, and necessary variations are implemented in the subclasses.
  • It controls the point(s) at which specialization is permitted. If the subclasses were to simply override the template method, they could make radical and arbitrary changes to the workflow. In contrast, by overriding only the hook methods, only certain specific details of the workflow can be changed, and the overall workflow is left intact.
abstract class Game
{
    abstract protected function initialize();
    abstract protected function startPlay();
    abstract protected function endPlay();

    public final function play()
    {
        $this->initialize();
        $this->startPlay();
        $this->endPlay();
    }
}

class Mario extends Game
{
    protected function initialize()
    {
        var_dump("Mario Game Initialized! Start playing.");
    }

    protected function startPlay()
    {
        var_dump("Mario Game Started. Enjoy the game!");
    }

    protected function endPlay()
    {
        var_dump("Mario Game Finished!");
    }

}

class Tankfight extends Game
{
    protected function initialize()
    {
        var_dump("Tankfight Game Initialized! Start playing.");
    }

    protected function startPlay()
    {
        var_dump("Tankfight Game Started. Enjoy the game!");
    }

    protected function endPlay()
    {
        var_dump("Tankfight Game Finished!");
    }

}

$game = new Tankfight();
$game->play();

$game = new Mario();
$game->play();

More details can be found on my Github profile here.