Featured image of post BP7 - Template Method - Learn Design Pattern From Simple Things

BP7 - Template Method - Learn Design Pattern From Simple Things

Porsche and Lamborghini are the children of Volkswagen. Their manufacturing process uses the same structure because they both implement the Volkswagen Template Method.

Template Method is a behavioral design pattern: šŸ–¤šŸ–¤šŸ–¤šŸ–¤šŸ–¤

What is Template Method?

The Template Method is a technique that allows you to define the outline template, skeleton of an algorithm while allowing the specifics of each step to be implemented by subclasses. It is a way to enforce a particular sequence of steps install_engine, assemble_chassis, paint_body for a process, or if the process involves multiple related operations that can be divided into sub-steps.

Template Method diagram

Why use Template Method?

There are several reasons why you might want to use the Template Method design pattern:

  • You can define the overall structure of an algorithm while allowing the details to be implemented by subclasses.
  • It allows you to reuse code in a flexible and customizable way.
  • You can avoid code duplication by having a single method for a particular sequence of steps.
  • You can ensure that the sequence of steps is always followed in the same way, even if the specifics of each step change.

Question: I hate the Template Method, what are the alternatives?

Answer: You can choose to code without using any specific pattern or use the Dependency Injection (DI) technique. This technique involves passing dependencies to a class or method as parameters, rather than having the class or method create the dependencies itself. The Volkswagen class can take in the engine, chassis, and body as parameters in its constructor, rather than having the class(Porsche, Lamborghini) create these dependencies itself.

Template Method

When to use Template Method?

Question: When should I use Template Method?

Answer: When concrete classes have the same structure. The main operation can be divided into sub-steps but maintains the same sequence.

Advantages:

  • Improved code reuse: By defining a template method that contains a sequence of steps and allowing subclasses to implement the details of each step, the Template Method design pattern promotes code reuse and reduces duplication.
  • Reduced code complexity: By breaking down a complex algorithm into smaller, more manageable steps, the Template Method design pattern can make the code easier to understand and maintain.
  • Increased flexibility: By allowing subclasses to implement the details of each step, the Template Method design pattern allows for more flexibility in how the algorithm is executed. This can be useful in situations where different implementations of the same algorithm are needed.

Disadvantages:

  • Tight coupling: The Template Method design pattern can lead to tight coupling between the abstract class and its concrete subclasses. This can make it difficult to change the structure of the algorithm without affecting the subclasses.
  • Limited extensibility: The Template Method design pattern provides a fixed structure for the algorithm, which can limit the ability to extend or modify it in the future.
  • Potential for code duplication: If the template method contains too much code or too many details, it can lead to duplication of code across the concrete subclasses.

Conclusion:

  • The Template Method design pattern is a powerful tool for designing software systems that require a fixed sequence of steps or a process involving multiple related operations. By defining a template method that contains a skeleton of the algorithm and allowing subclasses to implement the details of each step, the Template Method design pattern promotes code reuse, reduces complexity, and increases flexibility.
  • However, it’s important to be aware of the potential downsides of the Template Method design pattern, including tight coupling, limited extensibility, and the potential for code duplication. When deciding whether to use the Template Method design pattern or another design pattern, it’s important to carefully consider the specific requirements and constraints of the system being developed.

Input:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Lamborghini:
    def manufacture_car(self):
        self.install_engine()
        self.assemble_chassis()
        self.paint_body()

class Porsche:
    def manufacture_car(self):
        self.install_engine()
        self.assemble_chassis()
        self.paint_body()

Expected Output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Manufacturing Lamborghini:
Installing a powerful and loud engine
Assembling a lightweight and aerodynamic chassis
Painting the body with Volkswagen color


Manufacturing Porsche:
Installing a fast and smooth engine
Assembling a Volkswagen chassis
Painting the body with Volkswagen color

How to implement Template Method?

Non-Template Method implementation:

In this implementation, the Volkswagen class contains a manufacture_car method that is responsible for calling three other methods: install_engine, assemble_chassis, and paint_body. The install_engine method installs an engine, the assemble_chassis method assembles a chassis, and the paint_body method paints the body.

 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
class Volkswagen:
    def __init__(self, engine, chassis="Volkswagen", body="Volkswagen"):
        self.engine = engine
        self.chassis = chassis
        self.body = body

    def manufacture_car(self):
        self.install_engine()
        self.assemble_chassis()
        self.paint_body()

    def install_engine(self):
        print(f"Installing a {self.engine} engine")

    def assemble_chassis(self):
        print(f"Assembling a {self.chassis} chassis")

    def paint_body(self):
        print(f"Painting the body with {self.body} color")


if __name__ == "__main__":
    print("Manufacturing Lamborghini:")
    lamborghini = Volkswagen(
        engine="powerful and loud", chassis="lightweight and aerodynamic"
    )
    lamborghini.manufacture_car()
    print("\n")

    print("Manufacturing Porsche:")
    porsche = Volkswagen(engine="fast and smooth")
    porsche.manufacture_car()

Template Method Implementation:

The abstract class Volkswagen defines the skeleton of the algorithm in the manufacture_car method, which calls the primitive operations install_engine, assemble_chassis, and paint_body. The concrete subclasses Lamborghini and Porsche provide their own implementations for the install_engine and assemble_chassis operations, while leaving the default implementation of paint_body.

It separates the common behavior of manufacturing a Volkswagen car from the specific behavior of manufacturing a Lamborghini or a Porsche, which makes the code more modular and easier to maintain. Additionally, the use of abstract methods in the base class enforces the implementation of these methods in the concrete subclasses, which helps prevent errors and improve code reliability.

 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
from abc import ABC, abstractmethod


class Volkswagen(ABC):
    """The Abstract Class defines a template method that contains a skeleton of
    some algorithm, composed of calls to (usually) abstract primitive operations.

    Concrete subclasses should implement these operations, but leave the template
    method itself intact.
    """

    def manufacture_car(self) -> None:
        """The template method defines the skeleton of an algorithm."""
        self.install_engine()
        self.assemble_chassis()
        self.paint_body()

    @abstractmethod
    def install_engine(self) -> None:
        pass

    def assemble_chassis(self) -> None:
        print("Assembling a Volkswagen chassis")

    def paint_body(self) -> None:
        print("Painting the body with Volkswagen color")


class Lamborghini(Volkswagen):
    def install_engine(self) -> None:
        print("Installing a powerful and loud engine")

    def assemble_chassis(self) -> None:
        print("Assembling a lightweight and aerodynamic chassis")


class Porsche(Volkswagen):
    def install_engine(self) -> None:
        print("Installing a fast and smooth engine")


if __name__ == "__main__":
    print("Manufacturing Lamborghini:")
    lamborghini = Lamborghini()
    lamborghini.manufacture_car()
    print("\n")

    print("Manufacturing Porsche:")
    porsche = Porsche()
    porsche.manufacture_car()

Both the Template Method design pattern and the non-Template Method design pattern can be used to implement the functionality in the code above.

If the car manufacturing process requires a fixed sequence of steps and closely related operations, the Template Method design pattern can be a good choice.

However, if the car manufacturing process requires more flexibility, the non-Template Method design pattern can be more appropriate.

Source Code

Made with the laziness šŸ¦„
by a busy guy