## 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). ![template](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/copyright%20free%20drawings/Template.png) ### 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. ![template method](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/uml/template.png) 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.