“This is the 26th day of my participation in the August More Text Challenge.

preface

At the advanced end of the interview, there are often some questions about design patterns, and the answers are not good. Coincides with the activities of more challenges in August, I plan to spend a month to clarify the knowledge points about design patterns, to increase the confidence of my interview.

define

The template method pattern is a very simple pattern that can be implemented using inheritance alone.

The template method pattern consists of two parts, the first part is the abstract parent class, the second part is the concrete implementation child class.

An algorithm framework that encapsulates a subclass in an abstract superclass, including the implementation of some common methods and the execution order of all methods in the subclass.

By inheriting this abstract class, subclasses also inherit the entire algorithm structure and can choose to override the methods of the parent class.

Usage scenarios

In parallel subclasses, there are many identical behaviors among subclasses, but there are also different behaviors among subclasses, and both identical and different behaviors are implemented in a mix of subclasses. The template method pattern can be optimized to move the same parts of the subclass implementation into the parent class, leaving the different parts to be implemented by the subclass.

Abstract classes for headaches

First of all, the template method pattern is a design pattern that relies heavily on abstract classes. JavaScript does not provide support for abstract classes at the language level, and it is difficult to simulate the implementation of abstract classes. The concessions and flexibilities we have to make in the absence of abstract classes.

The role of abstract classes

Abstract class is a concept in Java. In Java, classes are divided into two kinds, one is concrete class, the other is abstract class. Concrete classes can be instantiated, but abstract classes cannot. Since abstract classes cannot be instantiated, if an abstract class is written, it must be inherited by some concrete class.

Use a life scenario to understand. If we go to a convenience store and want to buy a drink, we can’t just say to the owner, “Have a drink.” If we did, the next question would be, “What kind of drinks?” Beverage is just an abstract category, only when we really know the type of beverage, can we get a bottle of coffee, green tea, black tea, cola, etc.

Extraction method and specific method

Abstract methods are declared in abstract classes. Abstract methods have no concrete implementation and are “dumb” methods. When a subclass inherits the abstract class, it must override the parent class’s abstract methods. In addition to abstract methods, if each subclass has the same concrete implementation methods, those methods can also be placed in an abstract class to save code for reuse. These methods are called concrete methods. When code needs to change, we just need to change the concrete methods in the abstract class.

Resolve JavaScript to extract the image class does not support

JavaScript does not provide syntactic support for abstract classes. The first purpose of abstract classes is to hide the concrete type of an object, which is not important in JavaScript because JavaScript is a “type-fuzzy” language.

So when we use prototype inheritance in JavaScript to emulate Java’s class inheritance, there is no compiler to help us do any kind of checking, and there is no way to guarantee that subclasses will override “abstract methods” in their parent classes.

There is a very useful method. That is, throw an error in the method of the abstraction class.

Class Extraction{constructor(){} a(){throw new Error(' subclass must override a method '); }}Copy the code

While no errors are reported while writing the code, they are reported when running the code, just a little late.

Implement a simple template method pattern

Use a classic example to introduce. Coffee and tea.

First use the program to realize the process of making coffee:

Class Coffee{boilWater(){console.log(' boilWater '); } brewCoffeeGriends(){console.log(' Brew coffee with boiling water '); } pourInCup(){console.log(' Pour coffee into cup '); } addSugarAndMilk(){console.log(' addSugarAndMilk '); } init(){ this.boilWater(); this.brewCoffeeGriends(); this.pourInCup(); this.addSugarAndMilk(); } } const coffee = new Coffee(); coffee.init();Copy the code

Then use the program to realize the process of making tea.

Class Tea{boilWater(){console.log(' boilWater '); } steepTeaBag(){console.log(' steep tea in boiling water '); } pourInCup(){console.log(' Pour the tea into the cup '); } addLemon(){console.log(' addLemon '); } init(){ this.boilWater(); this.steepTeaBag(); this.pourInCup(); this.addLemon(); } } const tea = new Tea(); tea.init();Copy the code

Comparing these two programs, it can be found that the steps of making Tea and Coffee are actually similar. Coffee and Tea have the same behaviors, but there are some differences in details. The template method mode can be used to construct a type of Beverage. The behaviors in Coffee and Tea were separated out and moved to the Coffee class Beverage, which was taken as their parent class.

Make tea coffee Smoke as
The water to a boil The water to a boil The water to a boil
Brew coffee in boiling water Soak tea leaves in boiling water Soak the ingredients in boiling water
Pour the coffee into the cup Pour the tea into the cup Pour the drink into the glass
Add sugar and milk With lemon Add the ingredients

Let’s start by taking a snapshot and comparing the process of making tea and coffee

Make tea coffee
The water to a boil The water to a boil
Brew coffee in boiling water Soak tea leaves in boiling water
Pour the coffee into the cup Pour the tea into the cup
Add sugar and milk With lemon

You can find

  • The ingredients are different. One is coffee and one is tea, but we can abstract them both as “drinks.”
  • The way of soaking is different. Coffee is brewed, while tea is soaked. We can abstract them both as “brews”.
  • The spices are different. One is sugar and milk and one is lemon, but we can abstract them both as “ingredients.”

After abstraction, whether we make coffee or tea, we can organize it into the following four steps:

  • The water to a boil
  • Brew drinks with boiling water
  • Pour the drink into the glass
  • Add the ingredients

Create a Beverage that makes a cup of the Beverage

Class Beverage{constructor(){} boilWater(){console.log(' boil the water '); } brew(){// Brew with boiling water, empty method, should be overridden by subclass throw new Error(' subclass must overwrite brew method '); } pourInCup(){// Pour the drink into the cup, empty method, should be overridden by subclasses throw new Error(' subclasses must overwrite pourInCup method '); } addCondiments(){// addCondiments, empty method, should be overridden by subclasses throw new Error(' subclasses must overwrite addCondiments method '); } init(){ this.boilWater(); this.brew(); this.pourInCup(); this.addCondiments(); }}Copy the code

The process of making coffee and tea can inherit the Beverage.

class Coffee extends Beverage{ constructor(){ super(); } boilWater(){console.log(' boilWater '); } brew(){console.log(' brew coffee with boiling water '); } pourInCup(){console.log(' Pour coffee into cup '); } addCondiments(){console.log(' add sugar and milk '); } } const coffee = new Coffee(); coffee.init();Copy the code

This gives us the simplest template-style pattern, where the key is to extract methods from subclasses.