1.10. Template Method

1.10.1. Intent

According to the Gang of Four, the Template Method pattern is a way to “define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure” (Design Patterns: Elements of Reusable Object-Oriented Software, 2013, p.325).

As stated in the book, the Template Method pattern leads to an example of inversion of control (IoC) principle which is sometimes referred to as the Hollywood Principle: don’t call us, we’ll call you.

1.10.2. When to use it?

The Template Method pattern should be used in various cases:

  • you want to implement the invariant parts of a algorithm and give subclasses the ability to customize varying parts using method overriding
  • you are concerned about code duplication and you want to avoid it (see first bullet)
  • you have to control inheritance and how it is performed. Just the varying part of a method will be rewritten (it will not be entirely rewritten)

1.10.3. Diagram

Created using PhpStorm and yFiles.

Class diagram of the Template Method pattern

1.10.4. Implementation

AbstractOneManShow.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

namespace Phpatterns\Behavioral\TemplateMethod;

abstract class AbstractOneManShow
{
    /**
     * General algorithm
     */
    public function showMustGoOn()
    {
        $this->receiveThePublic();
        $this->doTheShow();
        $this->thankThePublic();
    }

    /**
     * This is an invariant part of the algorithm and it can't be modified.
     */
    final protected function receiveThePublic()
    {
        // ...
        // Check tickets, allocate seats, etc.
        // ...
    }

    /**
     * This will vary according to the artist
     */
    abstract protected function doTheShow();

    /**
     * There is a default behavior but every artist always has the
     * opportunity to thank the public as he wishes.
     */
    protected function thankThePublic()
    {
        // ...
        // Thank the audience
        // ...
    }
}

FirstOneManShow.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace Phpatterns\Behavioral\TemplateMethod\OneManShow;

use Phpatterns\Behavioral\TemplateMethod\AbstractOneManShow;

class FirstOneManShow extends AbstractOneManShow
{
    /**
     * This method MUST be implemented
     */
    protected function doTheShow()
    {
        echo 'First one man show!';
    }

    /**
     * This method CAN be implemented if needed
     */
    protected function thankThePublic()
    {
        // ...
        // Modify the default behavior to thank the audience
        // ...
    }
}

SecondOneManShow.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php

namespace Phpatterns\Behavioral\TemplateMethod\OneManShow;

use Phpatterns\Behavioral\TemplateMethod\AbstractOneManShow;

class SecondOneManShow extends AbstractOneManShow
{
    /**
     * This method MUST be implemented
     */
    protected function doTheShow()
    {
        echo 'Second one man show!';
    }
}

1.10.5. Tests

TemplateMethodTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace Test\Phpatterns\Behavioral\Strategy;

use Phpatterns\Behavioral\TemplateMethod\OneManShow;

class TemplateMethodTest extends \PHPUnit_Framework_TestCase
{
    public function testFirstOneManShow()
    {
        $firstOneManShow = new OneManShow\FirstOneManShow();
        $this->expectOutputString('First one man show!');
        $firstOneManShow->showMustGoOn();
    }
    public function testSecondOneManShow()
    {
        $secondOneManShow = new OneManShow\SecondOneManShow();
        $this->expectOutputString('Second one man show!');
        $secondOneManShow->showMustGoOn();
    }
}