ここでは、Abstract Factory パターンの PHP における実装サンプルを紹介しています。そもそも Abstruct Factory パターンとは、 ウィキペディア:Abstract Factory パターン では、
Abstract Factory パターンとは、関連するインスタンス群を生成するための API を集約することによって、複数のモジュール群の再利用を効率化することを目的とする。 日本語では「抽象的な工場」と翻訳される事が多い。
と説明がされていますが、プログラマー以外には意味不明です。
スポンサーリンク
PHP による Abstract Factory パターンの実装例
以下は、データベースの接続および切断を行う抽象クラスになります。この抽象クラスの中身をそれぞれのデータベースごとに実装していくことになります。
// データベースへの接続と切断を定義する抽象クラス abstract class Database_Abstract { protected $_connection; // データベースへの接続 abstract public function openConnection(); // データベースから切断 abstract public function closeConnection(); }
次に、上記の抽象クラスを派生させ、Oracle および Mysql への接続と切断を行うクラスを実装します。
Oracle への接続と切断の実装例
class Oracle_Database extends Database_Abstract { static public function CreateFactory() { return new Oracle_Database(); } public function openConnection() { // oracle データベースに接続する処理 $this->_connection = $oci_connect('パラメータ', ・・・); } public function closeConnection() { oci_close($this->_connection); $this->_connection = null; } }
Mysql への接続と切断の実装例
class Mysql_Database extends Database_Abstract { static public function CreateFactory() { return new Mysql_Database(); } public function openConnection() { // Mysql データベースに接続する処理 $this->_connection = mysqli_init(); mysqli_real_connect('パラメータ', ・・・); } public function closeConnection() { $this->_connection->close(); $this->_connection = null; } }
使用例
上記で実装した各々のデータベース接続クラスは次のようにインスタンスの生成を行います。
if($db == 'oracle') { // oracle への接続と切断 $factory = Oracle_Database::CreateFactory(); } else if($db == 'mysql') { // Mysql への接続と切断 $factory = Mysql_Database::CreateFactory(); } /* * 以降、データベースの違いを意識することはない */ // データベースへ接続 $factory->openConnection(); // データベースから切断 $factory->closeConnection();
ポイント
インスタンスの生成は派生クラスで実装した CreateFactory 静的メソッドの1か所で集約しています。そのため、ユーザーが Oracle への接続時の場合は、Oracle_Database::CreateFactory で返されるインスタンスを使用するというルールを順守する限り、誤って Mysql へ接続することを防止できます。
次に Oracle, Mysql それぞれの接続および切断は同一の呼び出し方法(メソッド)で実現可能であり、それぞれの実装を使用する側はデータベースごとの違いを意識する必要がありません。
問題点としては、同一のメソッド(ルール)で同一機能を実現するためには、機能(抽象クラスの抽象メソッド)が 増えると、すべての派生クラスの修正が必要であり、場合によっては呼び出し側の修正も必要となる点です(ライブラリ作成者としては億劫な気分になるときもあります)。
今回のサンプルでは、抽象クラスのメソッドには、接続と切断の機能だけを持つようにしていますが、抽象クラスではなくインターフェースでの定義に変更しても同じす。
データベースによって、各機能について対応していない場合には、例外を飛ばすような実装もあります。