【デザインパターン】Template Methodでロジックを共通化する

## はじめに  
今年の頭からデザインパターン の勉強をはじめました。最近インプットが過剰になってきたと感じたので、勉強したことのアウトプットの場としてTemplate Methodのまとめを書かせていただきました。読者の参考になれば幸いです。また、間違いっているところや気になる点があればご指摘いただければ嬉しいです。
## 目次  
- TemplateMethodを使うと何がうれしいか？  
- クラス図  
- DisplayFigureクラス  
- Circleクラス  
- Squareクラス  
- 実際に動かしてみる  
- ロジックを変更してみる  

## Template Methodを使うと何がうれしいか？  
Template Methodを使うことで**共通の処理を一つにまとめる**ことができ、あとでロジックを変更したいときに修正箇所を減らし、コードの保守性を高めることができます。この説明だけではわかりにくいと思うので、実際のプログラムで説明していきます。
## クラス図  
![クラス図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286861/3ad6fee9-84f9-1220-de2d-130f8db1eff8.png)
抽象クラスDisplayFigureを継承したCircle、Squareがあります。MainクラスはDisplayFigureクラスを介して子クラスのメソッドを利用します。

## DisplayFigureクラス  

```java: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();
    }
}


```
図形を表示する処理が実装されたクラスです。このクラスは抽象クラスで抽象メソッド`printFigure()`を実装しており、子クラスに実装を強制しています。`dispaly()`では上の３つのメソッドをひとまとめにしており、子クラスでの処理を共通化しています。ここで重要なのが`final`修飾子でこの修飾子がついたメソッドは子クラスでオーバーライドして書き換えることができません。このメソッドをそのまま利用してくださいという意図が読み取れるのではないでしょうか？
## Circleクラス  

```java:Circle.java  
public class Circle extends DisplayFigure {

    private char symbol;

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

    public void  printFigure() {
        System.out.print(symbol);
    }
}
```  
次にDisplayFigureクラスを継承したCircleクラスをみていきましょう。上位クラスで定義した`printFigure()`の中身を実装しています。ロジックは親クラスに実装されているので比較的シンプルな実装になっています。クラス作成時点で初期化された変数symbplの記号を用いて図形を表示しています。記号●で初期化されると以下のようになります。  

```java:実行例  
--  start!!  --
●
●●
●●●
●●●●
●●●●●
-- finish!!  --
```



## Squareクラス  

```java:Square.java
public class Square extends DisplayFigure {

    private char symbol;

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

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

このクラスも`Circle.java`同様に`DisplayFigure.java`を継承しています。このクラスを記号■で初期化すると以下の実行結果になります。このプログラムを動かすMainクラスは最後に説明します。

```java:実行例  
--  start!!  --
■
■■
■■■
■■■■
■■■■■
-- finish!!  --
```  
`Circle`と`Square`は三角形が●か■で描画されているかが違うだけで、あとは**共通の処理を行なっている**ことがわかります。
## 実際に動かしてみる  
Mainクラスを作成して実際に動かしてみましょう。  

```java:Main.java
public class Main {

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

```java:実行結果
--  start!!  --
●
●●
●●●
●●●●
●●●●●
-- finish!!  --
--  start!!  --
■
■■
■■■
■■■■
■■■■■
-- finish!!  --

```  
ここで注目してほしいのは**作成したインスタンスを抽象クラスの型の変数に代入している(アップキャスト)**点です。そして、子クラスのメソッドを直接呼び出さずに抽象クラスである、`DisplayFigure`クラスの`display()`を呼び出しています。このおかげで、ロジックを変更したい場合には、`DisplayFigure`クラスの`display()`を変更するだけで済みます。

## ロジックを変更してみる  
最後にロジックを変更してみましょう。これまでは三角形を表示してきたので、四角形で表示するプログラムに書き換えてみます。  

```java:変更後の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 final void display() {
        init();
        for(int i = 0; i < 5; i ++) {
            for(int j = 0; j <= i; j ++) {
                printFigure();
            }
            System.out.println();
        }
        finish();
    } */

    // 四角形を表示するプログラムに変更
    public final void display() {
        init();
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                printFigure();
            }
            System.out.println();
        }
        finish();
    }
}
```
実行すると…

```java:変更後の実行結果  
--  start!!  --
●●●●●
●●●●●
●●●●●
●●●●●
●●●●●
-- finish!!  --
--  start!!  --
■■■■■
■■■■■
■■■■■
■■■■■
■■■■■
-- finish!!  --

```
`DisplayFigure`クラスの`print()`を変更するだけで`Circle`と`Square`の２つのクラスの振る舞いを変更することができました。

---  
参考書籍: [増補改訂版Java言語で学ぶデザインパターン入門](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)