はじめに
今年の頭からデザインパターン の勉強をはじめました。最近インプットが過剰になってきたと感じたので、勉強したことのアウトプットの場としてTemplate Methodのまとめを書かせていただきました。読者の参考になれば幸いです。また、間違いっているところや気になる点があればご指摘いただければ嬉しいです。
目次
- TemplateMethodを使うと何がうれしいか?
- クラス図
- DisplayFigureクラス
- Circleクラス
- Squareクラス
- 実際に動かしてみる
- ロジックを変更してみる
Template Methodを使うと何がうれしいか?
Template Methodを使うことで共通の処理を一つにまとめることができ、あとでロジックを変更したいときに修正箇所を減らし、コードの保守性を高めることができます。この説明だけではわかりにくいと思うので、実際のプログラムで説明していきます。
クラス図
抽象クラスDisplayFigureを継承したCircle、Squareがあります。MainクラスはDisplayFigureクラスを介して子クラスのメソッドを利用します。
DisplayFigureクラス
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()
では上の3つのメソッドをひとまとめにしており、子クラスでの処理を共通化しています。ここで重要なのがfinal
修飾子でこの修飾子がついたメソッドは子クラスでオーバーライドして書き換えることができません。このメソッドをそのまま利用してくださいという意図が読み取れるのではないでしょうか?
Circleクラス
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の記号を用いて図形を表示しています。記号●で初期化されると以下のようになります。
-- start!! --
●
●●
●●●
●●●●
●●●●●
-- finish!! --
Squareクラス
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クラスは最後に説明します。
-- start!! --
■
■■
■■■
■■■■
■■■■■
-- finish!! --
Circle
とSquare
は三角形が●か■で描画されているかが違うだけで、あとは共通の処理を行なっていることがわかります。
実際に動かしてみる
Mainクラスを作成して実際に動かしてみましょう。
public class Main {
public static void main(String[] args) {
DisplayFigure circle = new Circle('●');
DisplayFigure square = new Square('■');
circle.display();
square.display();
}
}
-- start!! --
●
●●
●●●
●●●●
●●●●●
-- finish!! --
-- start!! --
■
■■
■■■
■■■■
■■■■■
-- finish!! --
ここで注目してほしいのは**作成したインスタンスを抽象クラスの型の変数に代入している(アップキャスト)**点です。そして、子クラスのメソッドを直接呼び出さずに抽象クラスである、DisplayFigure
クラスのdisplay()
を呼び出しています。このおかげで、ロジックを変更したい場合には、DisplayFigure
クラスのdisplay()
を変更するだけで済みます。
ロジックを変更してみる
最後にロジックを変更してみましょう。これまでは三角形を表示してきたので、四角形で表示するプログラムに書き換えてみます。
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();
}
}
実行すると…
-- start!! --
●●●●●
●●●●●
●●●●●
●●●●●
●●●●●
-- finish!! --
-- start!! --
■■■■■
■■■■■
■■■■■
■■■■■
■■■■■
-- finish!! --
DisplayFigure
クラスのprint()
を変更するだけでCircle
とSquare
の2つのクラスの振る舞いを変更することができました。
参考書籍: 増補改訂版Java言語で学ぶデザインパターン入門