Template pattern

Template pattern: belongs to behavioral design pattern, is one of the design patterns used more, more simple design pattern. While you may not yet know how to write in template mode, you may already have used it. Let’s start with a definition: Template pattern: Defines the skeleton of an algorithm in an operation and deferred some steps of the algorithm to subclasses so that subclasses can redefine specific steps of the algorithm without changing the structure of the algorithm. In plain English, I define some behavior rules in an abstract superclass, and specify the order in which these behavior rules are executed. As a subclass, you just need to implement the specifics of the behavior rules I define for your situation. Take a simple example: I have stipulated that the following things should be done before going to bed at night: lie in bed, brush your teeth, put on your pajamas, and the order of doing these things is to brush your teeth -> change your pajamas -> lie in bed, and you just need to do these things according to your actual situation, like

  • Someone uses black toothpaste and a regular toothbrush, then puts on silk pajamas and lies down on his Mattress
  • Someone uses Crest + electric toothpaste, then changes into the emperor’s new clothes and lies down on his bunk

Now as the music box listed company’s engineering department boss you, received the task from the superior, said that the customer wants to make music box!! And there were two of them. At this time, you disdain, (ˉ▽) just two, so easy. Here’s a standard design guide for music boxes

The original way

public abstract class MusicBox {

    // Turn on the switch
    abstract void start(a);

    // Play music
    abstract void sing(a);

    // The decorations on the music box begin to move, the windmill turns, and the characters dance
    abstract void action(a);

    // Turn off the switch
    abstract void end(a);

    // Make the music box work
    abstract void play(a);
}
Copy the code

Concrete realization of two kinds of music boxes:

public class Box1 extends MusicBox{
    @Override
    void start(a) {
        System.out.println("Turn on the start switch of the first music box.");
    }

    @Override
    void sing(a) {
        System.out.println("Play City in the sky.");
    }

    @Override
    void action(a) {
        System.out.println("The windmill on the music box is turning.");
    }

    @Override
    void end(a) {
        System.out.println("Turn off the start switch on the first music box.");
    }

    @Override
    void play(a) {
        this.start();
        this.sing();
        this.action();
        this.end(); }}public class Box2 extends MusicBox{
    @Override
    void start(a) {
        System.out.println("Turn on the start switch of the second music box.");
    }


    @Override
    void sing(a) {
        System.out.println("Playing my dream wedding.");
    }

    @Override
    void action(a) {
        System.out.println("Couple on the music box starts dancing.");
    }

    @Override
    void end(a) {
        System.out.println("Turn off the start switch for the second music box.");
    }

    @Override
    void play(a) {
        this.start();
        this.sing();
        this.action();
        this.end(); }}Copy the code

Demonstrate two types of music boxes to customers:

public class Client {
    public static void main(String[] args) {
        MusicBox box1 = new Box1();
        box1.play();
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        MusicBox box2 = newBox2(); box2.play(); }}Copy the code

Running results:

Wow, that seems to be the perfect client function. But a closer look shows that the methods used to make the music box work are exactly the same in the two music box implementation classes. Well, well, well, well, shouldn’t it be in the abstract superclass? All right? Come on, play it!

Template mode

public abstract class MusicBox {

    // Turn on the switch
    abstract void start(a);

    // Play music
    abstract void sing(a);

    // The decorations on the music box begin to move, the windmill turns, and the characters dance
    abstract void action(a);

    // Turn off the switch
    abstract void end(a);

    // Make the music box work
    public void play(a){
        this.start();
        this.sing();
        this.action();
        this.end(); }}public class Box1 extends MusicBox{
    @Override
    void start(a) {
        System.out.println("Turn on the start switch of the first music box.");
    }

    @Override
    void sing(a) {
        System.out.println("Play City in the sky.");
    }

    @Override
    void action(a) {
        System.out.println("The windmill on the music box is turning.");
    }

    @Override
    void end(a) {
        System.out.println("Turn off the start switch on the first music box."); }}public class Box2 extends MusicBox{
    @Override
    void start(a) {
        System.out.println("Turn on the start switch of the second music box.");
    }


    @Override
    void sing(a) {
        System.out.println("Playing my dream wedding.");
    }

    @Override
    void action(a) {
        System.out.println("Couple on the music box starts dancing.");
    }

    @Override
    void end(a) {
        System.out.println("Turn off the start switch for the second music box."); }}Copy the code

The presentation to the customer is the same as before:

public class Client {
    public static void main(String[] args) {
        MusicBox box1 = new Box1();
        box1.play();
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        MusicBox box2 = newBox2(); box2.play(); }}Copy the code

Running results:

Here’s what I said at the beginning:start(),sing(),action(),end()These are the rules, andplay()This is the order in which the rules are executed. This is the template pattern, isn’t it so easy? Using the template pattern results in the same way as the original method, and the template pattern reduces code redundancy and makes the code more concise.

To optimize the

  • In the template method, the basic method and design as far as possibleprotected, other properties and methods should not be set toprotected
  • In order to prevent malicious operation, template method a version will be addedfinalThe basic methods are the rules I mentioned above, and the template methods are the ways I define the order in which the rules are executed, so the above code can be written as:
public abstract class MusicBox {

    // Turn on the switch
    protected abstract void start(a);

    // Play music
    protected abstract void sing(a);

    // The decorations on the music box begin to move, the windmill turns, and the characters dance
    protected abstract void action(a);

    // Turn off the switch
    protected abstract void end(a);

    // Make the music box work
    final public void play(a){
        this.start();
        this.sing();
        this.action();
        this.end(); }}public class Box1 extends MusicBox{
    @Override
    protected void start(a) {
        System.out.println("Turn on the start switch of the first music box.");
    }

    @Override
    protected void sing(a) {
        System.out.println("Play City in the sky.");
    }

    @Override
    protected void action(a) {
        System.out.println("The windmill on the music box is turning.");
    }

    @Override
    protected void end(a) {
        System.out.println("Turn off the start switch on the first music box."); }}public class Box2 extends MusicBox{
    @Override
    protected void start(a) {
        System.out.println("Turn on the start switch of the second music box.");
    }


    @Override
    protected void sing(a) {
        System.out.println("Playing my dream wedding.");
    }

    @Override
    protected void action(a) {
        System.out.println("Couple on the music box starts dancing.");
    }

    @Override
    protected void end(a) {
        System.out.println("Turn off the start switch for the second music box."); }}Copy the code

The presentation to the customer is the same as before:

public class Client {
    public static void main(String[] args) {
        MusicBox box1 = new Box1();
        box1.play();
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        MusicBox box2 = newBox2(); box2.play(); }}Copy the code

Running results:

advantages

  • Encapsulate invariant parts and extend variable parts
  • Extract common parts of code for easy maintenance
  • The behavior is controlled by the parent class and implemented by the child class

disadvantages

  • Reversing our convention, the results of the execution of a subclass affect the results of the parent class, that is, the subclass affects the parent class
  • If the order of execution needs to change, modify the code of the abstract class

extension

After seeing the two music boxes in the demo, the customer put forward a new demand: some of the music boxes we play sky City have movable decorations, such as windmill and water wheel, while some have no movable decorations. What’s the matter? Looking at the customer’s demand, you fell into a deep thought. It is too waste of resources to open a new category for such a small difference. There must be some way to make this compatible

Hook method

Yes, you can make a music box produce different products based on different decorations by using hooks in an abstract class. Here, add a hook method to determine whether there are movable decorations to control, so we can modify it to look like this:

public abstract class MusicBox {

    // Turn on the switch
    protected abstract void start(a);

    // Play music
    protected abstract void sing(a);

    // The decorations on the music box begin to move, the windmill turns, and the characters dance
    protected abstract void action(a);

    // Turn off the switch
    protected abstract void end(a);

    // Determine if there is a movable decoration - the hook function here changes the internal result through external changes
    protected boolean haveActionThings(a){
        return true;
    }

    // Make the music box work
    final public void play(a){
        this.start();
        this.sing();
        if(this.haveActionThings()) {
            this.action();
        }
        this.end(); }}public class Box1 extends MusicBox{

    private boolean actionThingsTag = true;

    @Override
    protected void start(a) {
        System.out.println("Turn on the start switch of the first music box.");
    }

    @Override
    protected void sing(a) {
        System.out.println("Play City in the sky.");
    }

    @Override
    protected void action(a) {
        System.out.println("The windmill on the music box is turning.");
    }

    @Override
    protected void end(a) {
        System.out.println("Turn off the start switch on the first music box.");
    }

    @Override
    protected boolean haveActionThings(a) {
        return actionThingsTag;
    }
    public void setActionThingsTag(boolean actionThingsTag) {
        this.actionThingsTag = actionThingsTag; }}public class Box2 extends MusicBox{
    @Override
    protected void start(a) {
        System.out.println("Turn on the start switch of the second music box.");
    }


    @Override
    protected void sing(a) {
        System.out.println("Playing my dream wedding.");
    }

    @Override
    protected void action(a) {
        System.out.println("Couple on the music box starts dancing.");
    }

    @Override
    protected void end(a) {
        System.out.println("Turn off the start switch for the second music box."); }}public class Client {
    public static void main(String[] args) {
        Box1 box1 = new Box1();
        box1.play();
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        Box1 box11 = new Box1();
        box11.setActionThingsTag(false);
        box11.play();
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        Box2 box2 = newBox2(); box2.play(); }}Copy the code

Running results:

conclusion

The template method pattern is framed by the parent class, and the subclass overrides the parent class to make the subclass more focused on the implementation of business code. Important core algorithms can be designed as template methods, with other details implemented in subclasses.

One thousand readers have one thousand Hamlet, the above is purely in my personal learning experience, if there is any wrong, please point out, let me learn a wave, correct mistakes, thank you!