どんなもの?
オブジェクト生成する時のインターフェースだけを規定して、実際にどのクラスをインスタンス化するかはサブクラスで決めるようにするデザインパターン
イメージは共通部分をファクトリーで実装し、それ以外の処理をサブクラスで実装する、という感じ。
※既に学習したTemplate Methodに似ていると思ったら、Factory MethodはTemplate Methodの応用例だった。
参考
どんな時に使う?
例えば、以下のようなcsvファイルがあって
Music.csv
ルートヴィヒ・ヴァン・ベートーヴェン,ピアノソナタ第23番ヘ短調「熱情」
ヴォルフガング・アマデウス・モーツァルト,魔笛
ヴォルフガング・アマデウス・モーツァルト,セレナーデト長調 K.525「小夜曲」
アントニン・ドヴォルザーク,交響曲第9番ホ短調「新世界より」
このcsvファイルを順番に読み込んでブラウザに出力する処理は以下の通り
client.php
<html lang="ja">
<head>
<title>作曲家と作品たち</title>
</head>
<body>
<?php
$handle = fopen ("Music.csv","r");
$column = 0;
$tmp = "";
while ($data = fgetcsv ($handle, 1000, ",")) {
$num = count ($data);
for ($c = 0; $c < $num; $c++) {
if ($c == 0) {
if ($column != 0 && $data[$c] != $tmp) {
echo "</ul>";
}
if ($data[$c] != $tmp) {
echo "<b>" . $data[$c] . "</b>";
echo "<ul>";
$tmp = $data[$c];
}
}else {
echo "<li>";
echo $data[$c];
echo "</li>";
}
}
$column++;
}
echo "</ul>";
fclose ($handle);
?>
</body>
</html>
HTMLの中にPHPを書き、そのPHPの中でもcsvのopen(開く)とfgetcsv(データの取得)などいろんなことをしている。
問題点
このコードが一生CSVしか受け付けない、という仕様であることがほぼ確定しているのであれば問題ない。
問題なのはcsvではなくXMLデータでも出力対応したいという要件が出てきた場合。
その場合は読み込むファイルの判定とその後のデータ取得処理の違いをif文等で条件分岐を作ることになるので、client.phpが煩雑になる。
結果としてメンテナンス性がしにくいコードが出来上がってしまう...
この問題点を払しょくしてくれるのがFactory Methodになる
メリットは?
メリット=上記問題点の払拭方法となるが、それは 「オブジェクトの生成処理と使用処理を分離」 することになる
これにより、オブジェクトの生成についてはオブジェクトの利用側(クライアント側)を意識することなく開発ができるので利用側に大量のコードを書く必要がなくなりメンテナンス性が確保される。
またオブジェクトの利用側とオブジェクトのクラスの結びつきを低くすることにつながり、各クラスの役割がハッキリするので、仕様変更時の改修などによる影響範囲も最低限に済ませることができる。
使い方
上記のCSVを読み込み・出力するコードを例にFactory Methodを使って改修していく
イメージ
最終的なクラス図に落とし込むと以下のリンクの通りになる
※一般的なFactory Methodのクラス図は以下
改修の流れは大きく分けて5点。
- クライアントで呼び出すファイル読込みメソッド(read)、ファイル内容出力(display)を持つインターフェース(Reader.class.php)を作成
- Reader.class.phpをimplementsして、抽象メソッドであるread, displayの具体的な内容をCSVFileReader.class.phpに実装
- XMLファイルでも対応できるようにXMLファイル用のread, displayの処理内容を実装したXMLFileReader.class.phpを作成
- 今のままではファイルの種類を判別できないので、拡張子でファイルの種類を判別できる処理をReaderFactory.class.phpに実装
- 最後にファイル名の指定、ファイルの判別、オブジェクト作成、オブジェクトのデータ読み取り、データ出力をクライアントfactory_client.phpで作成・実装
Github
実装した内容はGithubで上げています。
所見
- 自分がよく使うLaravelでの活用方法としてはファットになりがちなControllerにて複数Controllerで同じ処理をしていた際はこのFactory Methodの採用を検討していいかと思った。
- あまりないと思うが今回のようにView(bladeファイル)にロジックを書いている場合も同様。
- (むしろ、Bladeにロジックを持たせない設計にした方がより良いが、、、)
- 今回のCSVとXMLの判別のような処理が必要ない時はよりシンプルなTemplate Methodでの実装も検討するべき