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.
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.