Skip to content

Template method

The Template Method pattern allows you to define the algorithm schema. Such a framework has a set of moving elements - unimplemented methods that can be overwritten. These parts should be used to define the algorithm.

template_method

Example

The following example implements a piece of code's performance test (although in reality one would have to take into account many additional factors). It measures the total execution time of a certain number of iterations.

KThe PerformanceTestTemplate class defines the framework of such an algorithm. It has 3 parts to define:

  • the getWarmUpIterationsNum method defines the number of warm-up (unmeasured) iterations
  • the getIterationsNum method defines the number of measured iterations
  • the iteration method contains the code whose execution time is being measured

The algorithm using these parts is defined in the run method. It runs first a certain number of warm-up iterations, and then the actual iterations, the execution time of which is measured in seconds. Finally, the screen shows the statistics.

The RandomListSortingPerformanceTest class extends the PerformanceTestTemplate class, which in a single iteration (of which there are 100) creates a list, adds a number of randomly generated numbers to it, and then sorts it. The StringBuilderAppendPerformanceTest class also extends the PerformanceTestTemplate class, while in a single operation adds a randomly generated character to the previously prepared string one hundred thousand times.

import time
import random


class PerformanceTestTemplate:
    def get_warmup_iterations_num(self):
        pass

    def get_iterations_num(self):
        pass

    def iteration(self):
        pass

    def run(self):
        for i in range(self.get_warmup_iterations_num()):
            self.iteration()

        iteration_execution_times = []

        for i in range(self.get_iterations_num()):
            start_timestamp = time.time()
            self.iteration()
            end_timestamp = time.time()
            iteration_execution_times.append(end_timestamp-start_timestamp)

        self.show_statistics(iteration_execution_times)

    def show_statistics(self, iteration_execution_times):
        print(f"Shortest iteration took: {min(iteration_execution_times)} s")
        print(f"Longest iteration took: {max(iteration_execution_times)} s")
        print(f"All iterations took: {sum(iteration_execution_times)} s")
class RandomListSortingPerformanceTest(PerformanceTestTemplate):
    NUMBERS_NUM = 100000

    def get_warmup_iterations_num(self):
        return 2

    def get_iterations_num(self):
        return 100

    def iteration(self):
        integers = []
        for i in range(RandomListSortingPerformanceTest.NUMBERS_NUM):
            integers.append(random.randint(0, 1000000000))

        integers.sort()
class StringAppendPerformanceTest(PerformanceTestTemplate):
    CHARS_NUM = 100000

    def get_warmup_iterations_num(self):
        return 2

    def get_iterations_num(self):
        return 100

    def iteration(self):
        str_ = ''
        for i in range(StringAppendPerformanceTest.CHARS_NUM):
            str_ += chr(random.randint(1, 128))
def main():
    test_template = RandomListSortingPerformanceTest()
    test_template.run()

    test_template = StringAppendPerformanceTest()
    test_template.run()


if __name__ == '__main__':
    main()
Program output:
Shortest iteration took: 0.29123616218566895 s
Longest iteration took: 0.5434036254882812 s
All iterations took: 31.46757936477661 s
Shortest iteration took: 0.2841529846191406 s
Longest iteration took: 0.44202184677124023 s
All iterations took: 30.136130332946777 s

Using the Template Method pattern allows you to reduce duplication of code that is written once and resides in the base class. However, it is closed to modification of the algorithm, and the potentially large number of abstract steps to define may complicate the implementation.