## Template Method Pattern
### Problem
Say you have two or more *almost* identical behaviors from different classes. Rewriting these object behaviors as separate methods for each class duplicates many parts of the code (especially if the behavior has a lot of lines of code).

### Solution
To avoid code duplication, you break down your code into individual steps. By doing this you can create a superclass that contains the implementation for all common steps. This superclass will also contain the common implementation for the **template method**, the method that combines all steps into the original object behavior. differences between steps will be resolved under different specializations of this superclass.

If the exact instance of the class is a `Specialization1`, it performs the template method with special versions of `step1()` and `step4()` (since `Specialization1` overrides them) but the other parts are inherited from the `Template`.
> The steps in the superclass can be a mix of abstract methods and concrete methods. Make a method abstract if you want to force all specializations to override these steps. You'll want to do these if some of the steps in your template doesn't have a default implementation.
### General Example
```python!
from abc import ABC, abstractmethod
class Template(ABC):
@abstractmethod
def step1(self): #this has to be overridden
pass
def step2(self): #this has a default behavior but can be overridden
print("step 2: do something by default (t)")
def step3(self): #this has a default behavior but can be overridden
print("step 3: do something by default (t)")
@abstractmethod
def step4(self): #this has to be overridden
pass
def templateMethod(self):
self.step1()
for i in range(3):
self.step2()
self.step3()
self.step4()
class Specialization1(Template):
def step1(self):
print("step 1: do something (s1)")
def step4(self):
print("step 4: do something (s1)")
class Specialization2(Template):
def step1(self):
print("step 1: do something else (s2)")
def step2(self):
print("step 2: do something special (s2)")
def step4(self):
print("step 4: do something else (s2)")
s1:Template = Specialization1()
s2:Template = Specialization2()
s1.templateMethod()
print()
print()
s2.templateMethod()
```
### Why this is elegant
- **Open/Closed Principle** - The `Template` is open for extension but closed for modification
- *Encapsulate what varies* - steps can vary from specialization to specialization, therefore they are encapsulated into step methods.
- Implementing this pattern will remove duplicate code in the common parts of the algorithm.
- Clients may override only certain steps in a large algorithm, making it easier to create specializations
### How to implement it
1. Create an abstract class called `Template`. It contains the method `templateMethod()` broken down into separate steps through separate `step1()`, `step2()`, ... and etc. methods. When invoked `templateMethod()` will just call these step methods.
2. Each step method inside `Template` will contain the default implementation of that step. If there is no default implementation, the method should be abstract.
3. For every similar behavior to `templateMethod()` a specialization of `Template` is created. These methods will implement all abstract methods and override all step methods that vary for its behavior.