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. The algorithm framework of a subclass is usually encapsulated 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.

The story background

We now need to brew a cup of coffee and a pot of tea, and the steps are basically the same, as shown below

coffee Make tea
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

Code implementation (inheritance)

/* Create an abstract superclass to represent the process of making a drink. We use the word Beverage */ var Beverage =function() {}; Beverage.prototype.boilWater =function(){ 
    console.log( 'Boil the water' );
};
Beverage.prototype.brew = function(){
    throw new Error( 'Subclasses must override brew methods' );
}; 
Beverage.prototype.pourInCup = function(){
    throw new Error( 'Subclasses must override the pourInCup method' );
}; 
Beverage.prototype.addCondiments = function(){
    throw new Error( 'Subclasses must override the addCondiments method' );
};
Beverage.prototype.init = function(){ this.boilWater(); this.brew(); this.pourInCup(); this.addCondiments(); }; /* Create a Coffee class */ var Coffee =function() {}; Coffee.prototype = new Beverage(); Coffee.prototype.brew =function(){ 
    console.log( 'Brew coffee in boiling water' );
};
Coffee.prototype.pourInCup = function(){
    console.log( 'Pour the coffee into the cup' );
};
Coffee.prototype.addCondiments = function(){ 
    console.log( 'With sugar and milk'); }; var Coffee = new Coffee(); Coffee.init(); /* Create the Tea class */ var Tea =function() {}; Tea.prototype = new Beverage(); Tea.prototype.brew =function(){ 
    console.log( 'Soak tea leaves in boiling water' );
};
Tea.prototype.pourInCup = function(){
    console.log( 'Pour the tea into the cup' );
};
Tea.prototype.addCondiments = function(){ 
    console.log( 'Add lemon' );
};
var tea = new Tea(); 
tea.init();
Copy the code

Consider: Is inheritance really necessary?

In the template method pattern, the parent class encapsulates the algorithm framework and method execution order of the subclass. After the subclass inherits the parent class, the parent class tells the subclass to execute these methods. This design technique is well illustrated by the Hollywood principle

Hollywood principle

There is no doubt that Hollywood is a paradise for actors, but it also has many new actors who can’t find work. Many new actors go home and wait for a call after handing over their resumes to the agencies. Sometimes, when the actor gets tired of waiting, he or she calls the acting company to ask about the situation, and the acting company often replies, “Don’t come to me, I’ll call you.” In design, such rules are known as the Hollywood principle. Under the guidance of this principle, we allow the underlying components to tied himself to the high-level component, and high-level component can decide when and how to use these underlying components, high-level component to treat the underlying components, new actors, with performing arts company is “don’t call us, we will call you”.

Code refactoring (The Hollywood Principle)

var Beverage = function( param ){
    var boilWater = function(){ 
        console.log( 'Boil the water' );
    };
    var brew = param.brew || function(){  
        throw new Error( 'Must pass brew method' );
    };
    var pourInCup = param.pourInCup || function(){ 
        throw new Error( 'pourInCup method must be passed' );
    };
    var addCondiments = param.addCondiments || function(){ 
        throw new Error( 'Must pass the addCondiments method' );
    };
    var F = function() {}; F.prototype.init =function(){ 
        boilWater();
        brew();
        pourInCup();  
        addCondiments();
     };
    return F; 
};
var Coffee = Beverage({ 
    brew: function(){
        console.log( 'Brew coffee in boiling water' ); 
    },
    pourInCup: function(){
        console.log( 'Pour the coffee into the cup' );
   },
   addCondiments: function(){
        console.log( 'With sugar and milk'); }}); var Tea = Beverage({ brew:function(){
        console.log( 'Soak tea leaves in boiling water' ); 
    },
    pourInCup: function(){
        console.log( 'Pour the tea into the cup' );
    },
    addCondiments: function(){
       console.log( 'Add lemon'); }}); var coffee = new Coffee(); coffee.init(); var tea = new Tea(); tea.init();Copy the code

conclusion

The template method pattern is a typical design pattern that encapsulates changes to improve system scalability. In traditional object-oriented language, in a program that uses the template method pattern, the class of methods and the order of execution are the same, so we abstract this logic into the template method of the parent class. However, how the methods of subclasses are implemented is variable, so we encapsulate this part of the changing logic in the subclass. By adding new subclasses, we can add new functionality to the system without changing the abstract parent class or other subclasses, which is consistent with the open  closed principle.

Series of articles:

JavaScript Design Patterns and Development Practices