Perl で、超フレキシブルな Factory パターンを考える。

Perl で、new しようとするクラスがなんでも OK の Factory クラスを考える。new しようとするクラスはパラメータ(なんと文字列)で与えられるという、かなり何でもアリの Factory クラスである。

まず、Factory クラスを作ってみる。パッケージ名を Twinkle として、この Factory クラスを Twinkle::PluginFactory としよう。名前は任意なので、Plugin という言葉が嫌ならば AddonFactory でも ModuleFactory でも ExtensionFactory でもいい。意味はすべて同じ。

モジュール名を Twinkle::PluginFacotry としたから、Perl の仕様によってこのコードのファイル名とディレクトリパスも決まる。Twinkle というディレクトリを新たに作って PluginFactory.pm というファイル名で以下のファイルを置く。

package Twinkle::PluginFactory; use strict; sub new { my $class = shift; my ($classname, $args_ref) = @_; return "Twinkle::Plugin::$classname"->new(%{$args_ref}); } 1;

このコードでのポイントは

return "Twinkle::Plugin::$classname"->new(%{$args_ref});

の1行に尽きる。Perl ではなんと ->new の前が文字列でもいいらしいのだ。

さて、Factory メソッドから呼び出されるクラス(個々の機能を持ったモジュール)は、Plugin ディレクトリの中に放り込みたい。実は上のコードはすでにそうなっている。return の行にある Twinkle::Plugin の部分がそれで、Twinkle::Plugin と決めうちにしたので、Twinkle ディレクトリの下に Plugin ディレクトリを作っておき、Factory で生成したいモジュールを入れておく。

さて、この Factory メソッドを呼び出すには、以下のようにする。このコードは Main.pm というファイル名(Main の部分は任意なので package Twinkle::App; と宣言すればファイル名は App.pm としてもよい)として Twinkle ディレクトリの中に置く。結果、Twinkle ディレクトリの中には Main.pm と PluginFactory.pm の 2つのファイルと、Plugin ディレクトリが置かれていることになる。

package Twinkle::Main; use Twinkle::PluginFactory; use Twinkle::Plugin::Foo; my $classname = 'Foo'; my $method = 'do'; my $value = Twinkle::PluginFactory->new( $classname, {
parent  =>  $self
} )->$method; 1;

この Main.pm では、Plugin ディレクトリの中にある Foo クラス(Foo モジュール)の do メソッドを呼び出している。ということは、Twinkle/Plugin ディレクトリには Foo.pm というファイル名があることが前提となる。つまり do メソッドを実装した Foo クラスの、Foo.pm という名前の Perl モジュール を作って呼び出して do メソッドから値を取得するという意味である。

このような Factory パターンのフレームワークを知っておくと、後から好きな名前、好きなメソッド名を実装したモジュールが追加可能となる。自分でも説明が下手だと思うのでちょっと難しいかも知れないが研究してみて欲しい。舌足らずなところがあることは認識しているので質問は随時受け付けます。