Skip to content

Template Method Design Pattern

Video Lecture

Section Video Links
Template Method Overview Template Method Overview Template Method Overview Template Method Overview 
Template Method Use Case Template Method Use Case Template Method Use Case Template Method Use Case 

Overview

...Refer to Book, Videos or Medium Membership for extra content.

Terminology

...Refer to Book, Videos or Medium Membership for extra content.

Template Method UML Diagram

Template Method UML Diagram

Source Code

...Refer to Book, Videos or Medium Membership for extra content.

./template/template_concept.py

 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# pylint: disable=too-few-public-methods
"The Template Method Pattern Concept"
from abc import ABCMeta, abstractmethod

class AbstractClass(metaclass=ABCMeta):
    "A template class containing a template method and primitive methods"

    @staticmethod
    def step_one():
        """
        Hooks are normally empty in the abstract class. The
        implementing class can optionally override providing a custom
        implementation
        """

    @staticmethod
    @abstractmethod
    def step_two():
        """
        An abstract method that must be overridden in the implementing
        class. It has been given `@abstractmethod` decorator so that
        pylint shows the error.
        """

    @staticmethod
    def step_three():
        """
        Hooks can also contain default behavior and can be optionally
        overridden
        """
        print("Step Three is a hook that prints this line by default.")

    @classmethod
    def template_method(cls):
        """
        This is the template method that the subclass will call.
        The subclass (implementing class) doesn't need to override this
        method since it has would have already optionally overridden
        the following methods with its own implementations
        """
        cls.step_one()
        cls.step_two()
        cls.step_three()

class ConcreteClassA(AbstractClass):
    "A concrete class that only overrides step two"
    @staticmethod
    def step_two():
        print("Class_A : Step Two (overridden)")

class ConcreteClassB(AbstractClass):
    "A concrete class that only overrides steps one, two and three"
    @staticmethod
    def step_one():
        print("Class_B : Step One (overridden)")

    @staticmethod
    def step_two():
        print("Class_B : Step Two. (overridden)")

    @staticmethod
    def step_three():
        print("Class_B : Step Three. (overridden)")

# The Client
CLASS_A = ConcreteClassA()
CLASS_A.template_method()

CLASS_B = ConcreteClassB()
CLASS_B.template_method()

Output

1
2
3
4
5
6
python ./template/template_concept.py
Class_A : Step Two (overridden)
Step Three is a hook that prints this line by default.
Class_B : Step One (overridden)
Class_B : Step Two. (overridden)
Class_B : Step Three. (overridden)

Template Method Example Use Case

...Refer to Book, Videos or Medium Membership for extra content.

Template Method Use Case UML Diagram

Template Method Use Case UML Diagram

Source Code

./template/client.py

1
2
3
4
5
6
7
8
9
"The Template Pattern Use Case Example"
from text_document import TextDocument
from html_document import HTMLDocument

TEXT_DOCUMENT = TextDocument()
TEXT_DOCUMENT.create_document("Some Text")

HTML_DOCUMENT = HTMLDocument()
HTML_DOCUMENT.create_document("Line 1\nLine 2")

./template/abstract_document.py

 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
43
44
45
46
47
48
49
50
51
52
"An abstract document containing a combination of hooks and abstract methods"
from abc import ABCMeta, abstractmethod

class AbstractDocument(metaclass=ABCMeta):
    "A template class containing a template method and primitive methods"

    @staticmethod
    @abstractmethod
    def title(document):
        "must implement"

    @staticmethod
    def description(document):
        "optional"

    @staticmethod
    def author(document):
        "optional"

    @staticmethod
    def background_colour(document):
        "optional with a default behavior"
        document["background_colour"] = "white"

    @staticmethod
    @abstractmethod
    def text(document, text):
        "must implement"

    @staticmethod
    def footer(document):
        "optional"

    @staticmethod
    def print(document):
        "optional with a default behavior"
        print("----------------------")
        for attribute in document:
            print(f"{attribute}\t: {document[attribute]}")
        print()

    @classmethod
    def create_document(cls, text):
        "The template method"
        _document = {}
        cls.title(_document)
        cls.description(_document)
        cls.author(_document)
        cls.background_colour(_document)
        cls.text(_document, text)
        cls.footer(_document)
        cls.print(_document)

./template/text_document.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
"A text document concrete class of AbstractDocument"
from abstract_document import AbstractDocument

class TextDocument(AbstractDocument):
    "Prints out a text document"
    @staticmethod
    def title(document):
        document["title"] = "New Text Document"

    @staticmethod
    def text(document, text):
        document["text"] = text

    @staticmethod
    def footer(document):
        document["footer"] = "-- Page 1 --"

./template/html_document.py

 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
"A HTML document concrete class of AbstractDocument"
from abstract_document import AbstractDocument

class HTMLDocument(AbstractDocument):
    "Prints out a HTML formatted document"
    @staticmethod
    def title(document):
        document["title"] = "New HTML Document"

    @staticmethod
    def text(document, text):
        "Putting multiple lines into there own p tags"
        lines = text.splitlines()
        markup = ""
        for line in lines:
            markup = markup + "    <p>" + f"{line}</p>\n"
        document["text"] = markup[:-1]

    @staticmethod
    def print(document):
        "overriding print to output with html tags"
        print("<html>")
        print("  <head>")
        for attribute in document:
            if attribute in ["title", "description", "author"]:
                print(
                    f"    <{attribute}>{document[attribute]}"
                    f"</{attribute}>"
                )
            if attribute == "background_colour":
                print("    <style>")
                print("      body {")
                print(
                    f"        background-color: "
                    f"{document[attribute]};")
                print("      }")
                print("    </style>")
        print("  </head>")
        print("  <body>")
        print(f"{document['text']}")
        print("  </body>")
        print("</html>")

Output

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
python ./template/client.py
----------------------
title   : New Text Document
background_colour       : white
text    : Some Text
footer  : -- Page 1 --

<html>
  <head>
    <title>New HTML Document</title>
    <style>
      body {
        background-color: white;
      }
    </style>
  </head>
  <body>
    <p>Line 1</p>
    <p>Line 2</p>
  </body>
</html>

Summary

...Refer to Book, Videos or Medium Membership for extra content.