絶版されているけれど、Google booksで公開されているのが見れます。
https://books.google.co.jp/books?id=sXNh4TeQeBIC&printsec=frontcover&hl=ja#v=onepage&q&f=false
1日1パターンってことで演習してアウトプットしていきます。
もくじ
使いどころ
- オブジェクト生成の為のAPIを定義し、クラスの継承を使って生成されるオブジェクトを切り替えることを目的とする。
今回のサンプルコードではCSVかXMLの拡張子によって生成されるクラスを切り替える役割を工場側(ReaderFactory.class.php)が担う。工場側が拡張子を判定子して利用するクラスを作成する
実装のポイント
- 利用側で利用するクラスを直接生成しない。
- 利用する側はCSVFileReaderクラスとXMLFileReaderクラスを意識することはない。
Factory Methodのメリット
- 拡張子が増えた場合も工場側(ReaderFactory.class.php)の処理を追加し、増えた拡張子を利用するクラスを作成するだけでよくなる。
data.csv
田中, おこめ 花田, とまと 花田, おくら 佐藤, おいも
data.xml
<?xml version="1.0" encoding="UTF-8"?> <farmers> <farmer name="田中"> <product name="おこめ" /> </farmer> <farmer name="花田"> <product name="とまと" /> </farmer> <farmer name="花田"> <product name="おくら" /> </farmer> <farmer name="佐藤"> <product name="おいも" /> </farmer> </farmers>
Reader.class.php
<?php /** * 読み込み機能を表すインターフェイス */ interface Reader { public function read(); public function display(); }
CSVFileReader.class.php
<?php require_once 'Reader.class.php'; /** * CSVファイルの読み込みを行うクラス */ class CSVFileReader implements Reader { /** * 内容を表示するファイル名 * * @access private */ private $filename; /** * データを扱うハンドラ名 * * @access private */ private $handler; /** * コンストラクタ * * @param string ファイル名 * @throws Exception */ public function __construct($filename) { if(!is_readable($filename)) { throw new Exception('file [' . $filename . '] is not readable !'); } $this->filename = $filename; } /** * 読み込みを行う */ public function read() { $this->handler = fopen($this->filename, 'r'); } /** * 文字コードの変換を行う */ private function convert($str) { return mb_convert_encoding($str, mb_internal_encoding(), 'auto'); } /** * 表示を行う */ public function display() { $column = 0; $tmp = ''; /** * Linux環境の場合、事前に適宜setlocale関数を使用して * ロケールを設定してください。 * 例) setlocale(LC_ALL, 'ja_JP.ujis'); */ while($data = fgetcsv($this->handler, 4096, ',')) { $num = count($data); for($i = 0; $i < $num; $i++) { if($i == 0 && $data[$i] != $tmp) { echo '</ul>'; } if($data[$i] != $tmp) { $tmp = $this->convert($data[$i]); echo '<b>' . $tmp . '</b>'; echo '<ul>'; } else{ echo '<li>'; echo $this->convert($data[$i]); echo '</li>'; } } $column++; } echo '</ul>'; fclose($this->handler); } }
XMLFileReader.class.php
<?php require_once 'Reader.class.php'; /** * XMLファイルの読み込みを行うクラス */ class XMLFileReader implements Reader { /** * 内容を表示するファイル名 * * @access private */ private $filename; /** * データを扱うハンドラ名 * * @access private */ private $handler; /** * コンストラクタ * * @param string ファイル名 * @throws Exception */ public function __construct($filename) { if(!is_readable($filename)) { throw new Exception('file [' . $filename . '] is not readable !'); } $this->filename = $filename; } /** * 読み込みを行う */ public function read() { $this->handler = simplexml_load_file($this->filename); } /** * 文字コードの変換を行う */ private function convert($str) { return mb_convert_encoding($str, mb_internal_encoding(), 'auto'); } /** * 表示を行う */ public function display() { foreach($this->handler->farmer as $farmer) { echo '<b>' . $this->convert($farmer['name']) . '</b>'; echo '<ul>'; foreach($farmer->product as $product) { echo '<li>'; echo $this->convert($product['name']); echo '</li>'; } echo '</ul>'; } } }
ReaderFactory.class.php
<?php require_once 'CSVFileReader.class.php'; require_once 'XMLFileReader.class.php'; /** * Readerクラスのインスタンス生成を行うクラス */ class ReaderFactory { /** * Readerクラスのインスタンスを生成する */ public function create($filename) { $reader = $this->createReader($filename); return $reader; } /** * Readerクラスのサブクラスを条件判定し、生成する */ private function createReader($filename) { $poscsv = stripos($filename, '.csv'); //指定文字列が見つからなかったらfalseと返る $posxml = stripos($filename, '.xml'); if($poscsv !== false) { $r = new CSVFileReader($filename); return $r; }elseif($posxml !== false){ return new XMLFileReader($filename); }else{ die('This filename is not supported : ' . $filename); } } }
index.php
<?php require_once 'ReaderFactory.class.php'; ?> <html lang='ja'> <head> <title>農家と作物</title> </head> <body> <?php /** * 入力ファイル */ //$filename = 'data.csv'; $filename = './data.xml'; $factory = new ReaderFactory(); $data = $factory->create($filename); $data->read(); $data->display(); ?> </body> </html>
/demo/Design-Pattern-Primer-by-PHP/FactoryMethod/