PHP

PHP Factory Methodパターン [PHPによるデザインパターン入門]

PHP

絶版されているけれど、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/

 

 

Amazonおすすめ

iPad 9世代 2021年最新作

iPad 9世代出たから買い替え。安いぞ!🐱 初めてならiPad。Kindleを外で見るならiPad mini。ほとんどの人には通常のiPadをおすすめします><

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)