Writing in the front

  • Take notes on learning design patterns
  • Improve the flexible use of design patterns

Learning to address

www.bilibili.com/video/BV1G4…

www.bilibili.com/video/BV1Np…

Refer to the article

C.biancheng.net/view/1317.h…

Program source codeGitee.com/zhuang-kang…

15. Template method pattern

15.1 Definition and characteristics of the template method pattern

The Template Method pattern is defined as follows: defining the skeleton of an algorithm in an operation and deferring some steps of the algorithm to a subclass so that the subclass can redefine specific steps of the algorithm without changing the structure of the algorithm. It is a behavioral pattern.

The main advantages of this mode are as follows.

  1. It encapsulates the immutable and extends the mutable. It encapsulates the algorithm which is considered to be the invariant part into the parent class, and inherits the algorithm of the variable part by the subclass, which is convenient for the subclass to continue to expand.
  2. It extracts common parts of the code in the parent class for easy code reuse.
  3. Some methods are implemented by subclasses, so subclasses can be extended to add functionality in accordance with the open closed principle.

The main disadvantages of this pattern are as follows.

  1. The need to define a subclass for each different implementation leads to an increase in the number of classes, a larger system, and a more abstract design, indirectly increasing the complexity of the system implementation.
  2. Abstract methods in the parent class are implemented by the subclass, and the results of the execution of the subclass affect the results of the parent class, leading to a reverse control structure that makes code more difficult to read.
  3. Due to the disadvantages of inheritance, if the parent class adds a new abstract method, all subclasses need to change it.

15.2 Structure and implementation of template method pattern

15.2.1 Structure of the template Method pattern

The Template Method pattern contains the following primary roles:

  • Abstract Class: Responsible for giving the outline and skeleton of an algorithm. It consists of a template method and several basic methods.

    • Template methods: Define the skeleton of an algorithm that calls its contained base methods in some order.

    • Basic method: is the implementation of the various steps of the algorithm method, is part of the template method. The basic methods can be divided into three categories:

      • Abstract Method: An Abstract Method is declared by an Abstract class and implemented by its concrete subclasses.

      • Concrete Method: A Concrete Method is declared and implemented by an abstract or Concrete class whose subclasses can override or inherit directly.

      • Hook methods: Abstract classes have been implemented, including logical methods for judgment and empty methods that need to be overridden by subclasses.

        A generic hook method is a logical method used for judgment. The name of the method is isXxx and the return value is Boolean.

  • Concrete Classes: Implement abstract methods and hook methods defined in abstract classes, which are the constituent steps of top-level logic.

15.2.2 Code implementation

AbstractClass

package com.zhuang.template;

/ * * *@Classname AbstractClass
 * @DescriptionAn abstract class *@Date 2021/3/26 20:06
 * @Created by dell
 */

public abstract class AbstractClass {
    public final void work(a) {
        Get up / /
        this.wake();
        / / brush your teeth
        this.brush();
        / / have breakfast
        this.breakfast();
        // Transportation
        this.transport();
        / / sleep
        this.sleep();
    }

    // Step as directly implemented
    public void wake(a) {
        System.out.println("Wake up...");
    }

    // Step as directly implemented
    public void brush(a) {
        System.out.println("Brush your teeth...");
    }

    // The steps are different (one is to eat bread and one is to drink milk)
    public abstract void breakfast(a);

    // The steps are different (one is by car, the other is by subway)
    public abstract void transport(a);

    // Step as directly implemented
    public void sleep(a) {
        System.out.println("Sleep..."); }}Copy the code

ConcreteClass_BreakFast

package com.zhuang.template;

/ * * *@Classname ConcreteClass_BreakFast
 * @DescriptionSpecific class breakfast class inheritance *@Date2021/3/26 were *@Created by dell
 */

public class ConcreteClass_BreakFast extends AbstractClass {
    @Override
    public void breakfast(a) {
        System.out.println("Eat bread...");
    }

    @Override
    public void transport(a) {
        System.out.println("Take the bus..."); }}Copy the code

ConcreteClass_Transport

package com.zhuang.template;

/ * * *@Classname ConcreteClass_Transport
 * @DescriptionTransportation class inheritance *@Date* 2021/3/26 yours@Created by dell
 */

public class ConcreteClass_Transport extends AbstractClass {
    @Override
    public void breakfast(a) {
        System.out.println("Drink milk...");
    }

    @Override
    public void transport(a) {
        System.out.println("By subway..."); }}Copy the code

Client

package com.zhuang.template;

/ * * *@Classname Client
 * @DescriptionTemplate method pattern test class *@Date2021/3/26 "*@Created by dell
 */

public class Client {
    public static void main(String[] args) {
        // Eat bread and take the bus
        System.out.println("On Monday");
        AbstractClass breakFast = new ConcreteClass_BreakFast();
        breakFast.work();

        System.out.println("= = = = = = = = = = = = = = = = = = = = = = = =");
        System.out.println("Friday");
        AbstractClass transport = newConcreteClass_Transport(); transport.work(); }}Copy the code

Hook method

AbstractClass

package com.zhuang.template.hook_method;

/ * * *@Classname AbstractClass
 * @DescriptionAn abstract class *@Date 2021/3/26 20:06
 * @Created by dell
 */

public abstract class AbstractClass {
    public final void work(a) {
        Get up / /
        this.wake();
        / / brush your teeth
        this.brush();
        / / have breakfast
        this.breakfast();
        // Transportation
        if (isSunday()) {
            this.transport();
        }
        / / sleep
        this.sleep();
    }

    // Step as directly implemented
    public void wake(a) {
        System.out.println("Wake up...");
    }

    // Step as directly implemented
    public void brush(a) {
        System.out.println("Brush your teeth...");
    }

    // The steps are different (one is to eat bread and one is to drink milk)
    public abstract void breakfast(a);

    // The steps are different (one is by car, the other is by subway)
    public abstract void transport(a);

    // Step as directly implemented
    public void sleep(a) {
        System.out.println("Sleep...");
    }

    // Whether the hook method is weekends without transportation
    boolean isSunday(a) {
        return false; }}Copy the code

ConcreteClass_BreakFast

package com.zhuang.template.hook_method;

/ * * *@Classname ConcreteClass_BreakFast
 * @DescriptionSpecific class breakfast class inheritance *@Date2021/3/26 were *@Created by dell
 */

public class ConcreteClass_BreakFast extends AbstractClass {
    @Override
    public void breakfast(a) {
        System.out.println("Eat bread...");
    }

    @Override
    public void transport(a) {
        System.out.println("Take the bus..."); }}Copy the code

ConcreteClass_Transport

package com.zhuang.template.hook_method;

/ * * *@Classname ConcreteClass_Transport
 * @DescriptionTransportation class inheritance *@Date* 2021/3/26 yours@Created by dell
 */

public class ConcreteClass_Transport extends AbstractClass {
    @Override
    public void breakfast(a) {
        System.out.println("Drink milk...");
    }

    @Override
    public void transport(a) {
        System.out.println("By subway..."); }}Copy the code

ConcreteClass_Sunday

package com.zhuang.template.hook_method;

/ * * *@Classname ConcreteClass_Sunday
 * @DescriptionWeekends free from work to achieve transportation method *@Date 2021/3/26 20:28
 * @Created by dell
 */

public class ConcreteClass_Sunday extends AbstractClass{

    @Override
    public void breakfast(a) {
        System.out.println("Eat bread or drink milk...");
    }

    @Override
    public void transport(a) {
        / / empty implementation
    }

    @Override
    boolean isSunday(a) {
        System.out.println("Today is the weekend, off...");
        return true; }}Copy the code

Client

package com.zhuang.template.hook_method;

/ * * *@Classname Client
 * @DescriptionThe template method tests the hook method@Date 2021/3/26 20:26
 * @Created by dell
 */

public class Client {

    public static void main(String[] args) {
        AbstractClass sunday = newConcreteClass_Sunday(); sunday.work(); }}Copy the code

15.3 Application Scenarios of the Template Method Mode

  1. When the overall steps of the algorithm are very fixed, but some parts of the algorithm are mutable, the template method pattern can be used to abstract the mutable parts out for subclass implementation.
  2. When multiple subclasses have common behavior, they can be extracted and grouped into a common parent class to avoid code duplication. First, you identify the differences in existing code and separate them into new operations. Finally, replace the different code with a template method that calls the new operations.
  3. When you need to control the extension of a subclass, the template method calls hook operations only at certain points, allowing extension only at those points.

15.4 JDK source code parsing

The InputStream class uses the template method pattern. There are multiple read() methods defined in the InputStream class, as follows:

public abstract class InputStream implements Closeable {
    // Abstract methods that require subclasses to be overridden
    public abstract int read(a) throws IOException;

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read(); // Calls the no-argument read method, which reads one byte at a time
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c; }}catch (IOException ee) {
        }
        returni; }}Copy the code

As you can see from the code above, the read() method without arguments is abstract and requires subclasses to be implemented. The read(byte b[]) method calls the read(byte b[], int off, int len) method, so the focus here is on methods that take three arguments.

In lines 18 and 27 of this method, you can see that the abstract read() method with no arguments is called.

The InputStream parent defines that reading a byte array reads len bytes at a time, one byte at a time, and stores it in the first index of the array. How do you actually read a byte of data? Implemented by subclasses.

Write in the last

  • If my article is useful to you, please give me a click 👍, thank you 😊!
  • If you have any questions, please point them out in the comments section! 💪