This is the sixth day of my participation in the August More text Challenge. For details, see:August is more challenging

Introduction: In this article we explain the template method model, we learn the template method with coffee and tea brewing. Another example of a design pattern for coffee is the Head First design pattern — decorator pattern

Without further ado, let’s go into template method mode.

Brew coffee and tea

Steps to make coffee:

(1) Boil the water

(2) Brew coffee with boiling water

(3) Put the coffee into the cup

(4) Add sugar and milk

The steps of making tea

(1) Boil the water

(2) Soak the tea in boiling water

(3) Put the tea into the cup

(4) Add lemon

Implement two classes for brewing coffee and tea

public class Coffee { public void PrepareRecipe() { BoilWater(); BrewCoffeeGrinds(); PourInCup(); AddSugarAndMilk(); } public void BoilWater() {console. WriteLine(" BoilWater "); } public void BrewCoffeeGrinds() {console.writeline (" brew coffee with boiling water "); } public void PourInCup() {console. WriteLine(" coffee into the cup "); } public void AddSugarAndMilk() {console. WriteLine(" AddSugarAndMilk "); }}Copy the code

  

public class Tea { public void PrepareRecipe() { BoilWater(); SteepTeaBag(); PourInCup(); AddLemon(); } public void BoilWater() {console. WriteLine(" BoilWater "); } public void SteepTeaBag() {Console.WriteLine(" SteepTeaBag "); } public void PourInCup() {console. WriteLine(" tea into the cup "); } public void AddLemon() {console. WriteLine(" AddLemon "); }}Copy the code

We found some duplicate code from these two classes, and duplicate code means we need to sort out our implementation or our design. The code for coffee and tea has the same methods in step 1 and step 3. The other two methods are unique to each other, so we can abstract the same method into the same base class. It might look something like this

Coffee and tea have their own proprietary methods, placed in their own classes, with each subclass covering the PrepareRecipe() method and implementing its own brew.

 

Second, further improvement

Through the above inheritance transformation we feel whether there is still some common methods are not encapsulated cleanly, there is something in common that is not encapsulated. How do we abstract the PrepareRecipe() method? The steps in both coffee and tea are the same. We’re pulling away from each subclass

The first problem is that coffee and tea are brewed in different ways, so give them a new name Brew(), and then use this name for both brewing and steeping. We also did the same with a new method name, AddCondiments(). The PrepareRecipe() method is thus reconstructed as follows:

        public void PrepareRecipe()
        {
            BoilWater();
            Brew();
            PourInCup();
            AddCondiments();
        }
Copy the code

② We now have the new PrepareRecipe() method and need to make it fit into the code, so we’re reworking the parent CoffeineBeverage

public abstract class CoffeineBeverage { public void PrepareRecipe() { BoilWater(); Brew(); PourInCup(); AddCondiments(); } public abstract void AddCondiments(); public abstract void Brew(); Private void BoilWater() {console. WriteLine(" BoilWater "); } private void PourInCup() {console. WriteLine(" tea into the cup "); }}Copy the code

③ Finally, we need to deal with coffee and tea classes so that they inherit the parent class, to achieve their own unique methods.

Public class Coffee: CoffeineBeverage {public override void Brew() {console. WriteLine(" CoffeineBeverage "); } public override void AddCondiments() {console. WriteLine(" add sugar and milk "); }} public class Tea:CoffeineBeverage {public override void Brew() {console. WriteLine(" boiled Tea "); } public override void AddCondiments() {console. WriteLine(" add lemon "); }}Copy the code

3. Template method pattern

Basically, the template method pattern is what we implement through the second step of improvement. PrepareRecipe() is our abstract template method.

(1) It is a method

(2) It serves as a template for an algorithm, which in this case is used to make the drink. In this template, each step within the algorithm is represented by a method. Some methods are handled by the parent class, others by the child class, and methods that need to be handled by the child class are defined as abstract methods in the parent class.

Definition:

Template method pattern: Define the skeleton of an algorithm in a method, deferring some steps to subclasses. The template approach allows subclasses to redefine certain steps in an algorithm without changing the structure of the algorithm.

Class diagram:

 

4. Template hooks

A hook is a method that is declared in an abstract class, but has an empty or default implementation. Hooks exist to give subclasses the ability to hook different points in an algorithm. It’s up to the subclass to decide whether to hook or not.

For example, you can decide whether you need to add lemon to your tea

public abstract class CoffeineBeverage { public void PrepareRecipe() { BoilWater(); Brew(); PourInCup(); if (CustomerWantsCondiments()) { AddCondiments(); } } public virtual bool CustomerWantsCondiments() { return true; } public abstract void AddCondiments(); public abstract void Brew(); Private void BoilWater() {console. WriteLine(" BoilWater "); } private void PourInCup() {console. WriteLine(" tea into the cup "); }}Copy the code

Tea without lemon

public class Tea : CoffeineBeverage { public override bool CustomerWantsCondiments() { return false; } public override void Brew() {console. WriteLine(" boiled tea "); } public override void AddCondiments() {console. WriteLine(" add lemon "); }}Copy the code

Testing:

5. Hollywood Principles

The template method model involves Hollywood principles

Hollywood rule: Don’t call us, we’ll call you.

The Hollywood principle is a way to prevent “dependence on corruption”. Dependency corruption occurs when higher-level components depend on lower-level components, which in turn depend on higher-level components. In this case, it is difficult for anyone to understand the design and maintenance of the system.

Under the Hollywood principle, we allow lower-level components to hook themselves into the system, and higher-level components decide when and how to use those lower-level components. In other words, high-level components treat low-level components as “don’t call us, we’ll call you.”

Here’s how our template method pattern follows this design principle: CoffeineBeverage is our high-level component that controls the brewing algorithm and calls subclasses only if they need to implement a method. The Coffee and Tea subclasses do not call the abstract superclass directly, but simply provide some details to implement themselves.