[JAVA] [Design pattern] Common logic with Template Method

Introduction

I started studying design patterns from the beginning of this year. Recently, I felt that the input became excessive, so I wrote a summary of the Template Method as a place to output what I learned. I hope it will be helpful to the reader. Also, I would be grateful if you could point out any mistakes or concerns.

table of contents

--What makes you happy with the Template Method? --Class diagram --DisplayFigure class --Circle class --Square class --Actually move --Try changing the logic

What makes you happy with the Template Method?

By using the Template Method, you can ** combine common processes into one **, reduce the number of modifications when you want to change the logic later, and improve the maintainability of the code. I think it is difficult to understand from this explanation alone, so I will explain it with an actual program.

Class diagram

クラス図.png There are Circle and Square that inherit from the abstract class DisplayFigure. The Main class uses the methods of the child class via the DisplayFigure class.

DisplayFigure class

DisplayFigure.java


public abstract class  DisplayFigure {

    public  void init() {
        System.out.println("--  start!!  --");
    }

    public abstract void printFigure();

    public  void finish() {
        System.out.println("-- finish!!  --");
    }

    public void final display() {
        init();
        for(int i = 0; i < 5; i ++) {
            for(int j = 0; j <= i; j ++) {
                printFigure();
            }
            System.out.println();
        }
        finish();
    }
}


This class implements the process of displaying figures. This class is an abstract class that implements the abstract method printFigure () and forces its child classes to implement it. In dispaly (), the above three methods are grouped together, and the processing in the child class is standardized. The important thing here is the final qualifier, and methods with this qualifier cannot be overridden and rewritten in child classes. Isn't it possible to read the intention to use this method as it is?

Circle class

Circle.java


public class Circle extends DisplayFigure {

    private char symbol;

    public Circle(char symbol) {
        this.symbol = symbol;
    }

    public void  printFigure() {
        System.out.print(symbol);
    }
}

Next, let's look at the Circle class that inherits the DisplayFigure class. It implements the contents of printFigure () defined in the upper class. Since the logic is implemented in the parent class, it is a relatively simple implementation. The figure is displayed using the symbol of the variable symbpl that was initialized at the time of class creation. When initialized with the symbol ●, it becomes as follows.

Execution example


--  start!!  --
●
●●
●●●
●●●●
●●●●●
-- finish!!  --

Square class

Square.java


public class Square extends DisplayFigure {

    private char symbol;

    public Square(char symbol) {
        this.symbol = symbol;
    }

    public void printFigure() {
        System.out.print(symbol);
    }
}

This class inherits DisplayFigure.java as well as Circle.java. Initializing this class with the symbol ■ yields the following execution results. The Main class that runs this program is explained at the end.

Execution example


--  start!!  --
■
■■
■■■
■■■■
■■■■■
-- finish!!  --

You can see that Circle and Square are doing ** common processing **, only the difference is whether the triangle is drawn with ● or ■.

I will actually move it

Let's create a Main class and actually run it.

Main.java


public class Main {

    public static void main(String[] args) {
        DisplayFigure circle = new Circle('●');
        DisplayFigure square =  new Square('■');
        circle.display();
        square.display();
    }
}

Execution result


--  start!!  --
●
●●
●●●
●●●●
●●●●●
-- finish!!  --
--  start!!  --
■
■■
■■■
■■■■
■■■■■
-- finish!!  --

What you should pay attention to here is that ** the created instance is assigned to a variable of the type of abstract class (upcast) **. Then, instead of calling the methods of the child class directly, the abstract class display () of the DisplayFigure class is called. Thanks to this, if you want to change the logic, you only have to change the display () of the DisplayFigure class.

Try changing the logic

Finally, let's change the logic. So far, we have displayed triangles, so let's rewrite it to a program that displays rectangles.

Display Figure after change.java


public abstract class DisplayFigure {

    public void init() {
        System.out.println("--  start!!  --");
    }

    public abstract void printFigure();

    public void finish() {
        System.out.println("-- finish!!  --");
    }

    /*  public final void display() {
        init();
        for(int i = 0; i < 5; i ++) {
            for(int j = 0; j <= i; j ++) {
                printFigure();
            }
            System.out.println();
        }
        finish();
    } */

    //Changed to a program that displays rectangles
    public final void display() {
        init();
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                printFigure();
            }
            System.out.println();
        }
        finish();
    }
}

When you run ...

Execution result after change


--  start!!  --
●●●●●
●●●●●
●●●●●
●●●●●
●●●●●
-- finish!!  --
--  start!!  --
■■■■■
■■■■■
■■■■■
■■■■■
■■■■■
-- finish!!  --

I was able to change the behavior of the two classes, Circle and Square, simply by changing the print () of the DisplayFigure class.


Reference book: [Introduction to Design Patterns Learned in the Augmented and Revised Java Language](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8 % 82% E7% 89% 88Java% E8% A8% 80% E8% AA% 9E% E3% 81% A7% E5% AD% A6% E3% 81% B6% E3% 83% 87% E3% 82% B6 % E3% 82% A4% E3% 83% B3% E3% 83% 91% E3% 82% BF% E3% 83% BC% E3% 83% B3% E5% 85% A5% E9% 96% 80-% E7% B5% 90% E5% 9F% 8E-% E6% B5% A9 / dp / 4797327030 / ref = sr_1_1? __mk_ja_JP =% E3% 82% AB% E3% 82% BF% E3% 82% AB% E3% 83% 8A & crid = 3V4BASNVFTA6O & keywords =% E3% 83% 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% 91% E3% 82% BF% E3% 83% BC% E3 % 83% B3 & qid = 1564625886 & s = gateway & sprefix =% E3% 81% A7% E3% 81% 96% E3% 81% 84% E3% 82% 93% E3% 81% B1% E3% 81% 9F% 2Caps% 2C301 & sr = 8-1)

Recommended Posts

[Design pattern] Common logic with Template Method
Design pattern ~ Template Method ~
Ruby design pattern template method pattern memo
C # chewed design pattern: Template Method
Template Method pattern
Template Method Pattern
Design pattern ~ Factory Method ~
Java8 Lambda expression & Stream design pattern reconsideration --Template Method pattern -
Java beginner design pattern (Factory Method pattern)
Design pattern ~ Builder ~
Design pattern ~ Visitor ~
Java design pattern
Design pattern ~ Proxy ~
Design pattern ~ State ~
Factory Method Pattern
Design pattern ~ Strategy ~
Design pattern ~ Composite ~
Design pattern (1): AbstractFactory
Design pattern ~ Iterator ~
Design pattern ~ Facade ~
Design pattern ~ Bridge ~
Design pattern ~ Mediator ~
Design pattern ~ Decorator ~
Design pattern ~ Interpreter ~
Factory Method pattern
Design pattern ~ Observer ~
Design pattern ~ Prototype ~
Design pattern ~ Memento ~
Design pattern ~ Adapter ~
Design pattern ~ Flyweight ~
C ++ design pattern (TemplateMethod pattern)
Design pattern ~ Abstract Factory ~
GoF design pattern summary
Java design pattern summary
Rethinking design patterns with Java8 lambda expressions & Stream --Builder pattern -
[Note] Design pattern considered when automating GUI test with Selenium