ここでは、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 それぞれの接続および切断は同一の呼び出し方法(メソッド)で実現可能であり、それぞれの実装を使用する側はデータベースごとの違いを意識する必要がありません。
問題点としては、同一のメソッド(ルール)で同一機能を実現するためには、機能(抽象クラスの抽象メソッド)が 増えると、すべての派生クラスの修正が必要であり、場合によっては呼び出し側の修正も必要となる点です(ライブラリ作成者としては億劫な気分になるときもあります)。
今回のサンプルでは、抽象クラスのメソッドには、接続と切断の機能だけを持つようにしていますが、抽象クラスではなくインターフェースでの定義に変更しても同じす。
データベースによって、各機能について対応していない場合には、例外を飛ばすような実装もあります。