読者です 読者をやめる 読者になる 読者になる

Factory MethodとAbstract Factory

考え事

以前のエントリへのコメントで、Abstract Factoryパターンなんてのを聞いて、その足で結城さんのデザインパターン本を買いに行った。(まぁ、その時知ったという時点であれなんだが。)

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

で、Abstract Factoryの項を読み、ふむふむと思ったんだが、ちょっとまとめてみる。(ごめんなさい、半分自分宛のメモなのでわけわからないかも。)

まずFactory Methodは、Factoryクラスのサブクラスで結論(=製品)のインスタンスを作るパターン。Factoryクラス内で必要なメソッドが抽象メソッドとして定義されているので、適切なサブクラスを選んでコンストラクタを呼び出しさえすれば、作られたインスタンスに対する操作は全く同じで良いというものだ。

結城さんの例だと、Factoryクラスのcreateメソッドがインスタンス生成のメソッドで、これはFactoryクラス内に実装されているのでサブクラスに任せている訳ではなさそうなんだが、よく見ると中でcreateProductとregisterProductを呼んでいて、これらはFactoryクラス内だと抽象メソッドなので、結果的にサブクラスでこれらを実装しないと使えない。

ちょっと話がそれるが、Javaだとこの抽象というものを確実に、強制力を持って記述することが出来る。これはPerlだけだとちょっとイメージしづらいかもと感じた。Perlの場合、抽象クラスやら抽象メソッドなんていっても強制力がないので、きちんと認識しながら書かないと意味がない。

『サブクラスで実装しないと使えない』=『Template Method』ということなのだな。同じ書き方だと『コンストラクタがTemplate Method』=『Factory Method』ということだ。

Abstract Factoryも似ているが、ちょっと複雑さが増していて難解。最初『抽象的部品』が鍵かと思ったが、どうもそれだけではない。(もちろん、何が部品なのかを考えることは重要だと思ったのだが。)Abstract Factoryの面白い点は、Factoryが外部から切り替え可能である事かもしれない。

結城さんの例だと、getFactoryメソッドでFactory(のサブクラス)のインスタンスを得るのだが、このメソッドの引数でインスタンスとするFactoryのサブクラスを外から指定している。このため、コマンドライン(=外部)から処理を差し替えられる。

Abstract FactoryのFactoryクラスもgetFactoryの他は抽象メソッドになっているのでそのままでは使えない。したがって、継承してサブクラス内で実装する訳だ。この『使用可能な』Factoryのサブクラスを外部から選べるので、その先の処理もごっそりと差し替えることが可能になる。

JavaだとnewInstanceメソッドといったなんだか不思議な?ものを使っているが、こういったことはPerlでは簡単。変数をクラス名と見なして普通にコンストラクタを呼ぶだけだ。

my $factory = new $classname;

とかとか。もちろん事前にロードしておかないとダメだが。例えば

eval{ require $classname; };
die "WRONG CLASS NAME : $classname = $@" if $@;
my $factory = new $classname;

とかやるのかな。トラップの部分をともかくとするならば、my $factory = new $classname;はPerlらしいスマートな書き方だと思う。

なお、これを知った上で自分のコードを読んでみると、Factory MethodというよりAbstract Factoryになりかけているようなコードも結構見かける。Factory Methodみたいなもんだと思って書いていたのだが、コンストラクタを呼び出すクラス名が動的に変わっていたりする訳だ。ただ実装が半端なので、何か混乱を来しているらしい。

まだなんか釈然としない部分はあるのだが、日を変えて何回か読み返してみると、理解が深まるかも。早速コーディングにも応用したいのではあるが、もうちょっと飲み込んでからでないとさらに混乱しそうな予感。