4. FactoryMethod パターン
デザインパターン 4章 FactoryMethod パターン
4.1 FactoryMethodパターンとは第4章では、FactoryMethod パターンを紹介します。FactoryMethod パターンは、オブジェクトの生成方法に一工夫加えることで、より柔軟にオブジェクトを生成することを目的とするものです。FactoryMethod パターンでは、インスタンスの生成をサブクラスに行わせることで、より柔軟に生成するインスタンスを選択することが可能となります。 オブジェクトを生成する場合、下記のように記述するのが普通です。 Product product = new Product(); しかし、このようなオブジェクト生成方法では、十分に満足のいく結果が得られないことがあります。 そこで、FactoryMethodパターンでは、オブジェクトの生成を担うメソッド(factory method)を通して間接的にオブジェクトを生成します。
public Product factoryMethod(){
return new Product();
}
このようなオブジェクト生成方法は、直接new Product()としてオブジェクトを生成する場合に比べ、より柔軟な結果をもたらします。 それでは、サンプルケースを見てみましょう。 4.2 サンプルケースサンプルケースでは、前回の TemplateMethod パターンに引き続き、生徒たちに版画クラスを作成させることを目的としましょう。前回と違うのは、「親クラスでは版材を与えないようにする」という点です。TemplateMethod パターンの親クラスである WoodCutPrint クラスでは、以下のようにして版材を与えていました。 private Cuttable hanzai = new Wood(); しかし、いつも人とは違ったことをしたがる今川君が「先生、僕は木じゃなくて芋に彫りたい」と言ってきたのです。生徒の自由な発想を大切にしたいと常日頃考えているあなたは、この申し出を受け入れたいと思い、親クラスを変更することにしました。
まずは、TemplateMethod パターンで使用した CutPrint クラスを見てみましょう。このクラスを利用して、hanzai の型の決定をサブクラスに任せられるようにすることが目的です。 public abstract class CutPrint{
public void draw( Cuttable hanzai );
public void cut( Cuttable hanzai );
public void print( Cuttable hanzai );
public void createCutPrint(){
Wood hanzai = ・・・
draw( hanzai );
cut( hanzai );
print( hanzai );
}
}
さて、何が問題になるでしょう? 上リストで、赤色で示している部分では、どのクラスのインスタンスが生成されるかは決定したくありません。なぜなら、生成するインスタンスの実際の型を決めてしまうと、サブクラスで自由に生成するインスタンスの型を決定することができないからです。createCutPrint をサブクラスでオーバーライドすればサブクラスで自由にインスタンスの型を決定することができますが、これでは、TemplateMethod の利点が失われてしまいます。 これを解決する方法として、FactoryMethod パターンが与えられます。FactoryMethod パターンでは、インスタンス生成のためのメソッドを用意します。そして、そのインスタンスを生成するためのメソッドを通してインスタンスの生成を行います。 具体的には、以下のようなソースコードとなります。 public abstract class CutPrint{
private void draw( Cuttable hanzai );
private void cut( Cuttable hanzai );
private void print( Cuttable hanzai );
private Cuttable createCuttable(){
return new Wood();
}
public void createCutPrint(){
Cuttable hanzai = createCuttable();
draw( hanzai );
cut( hanzai );
print( hanzai );
}
}
このように、インスタンスを生成するメソッドを通して、インスタンスを生成するようにしておくことで、 今川君は、createCuttable メソッドをオーバーライドするメソッドを記述し、版材を自由に選択することができるようになります。実際にソースコードを見てみましょう。 public class ImagawasCutPrint extends CutPrint{
private draw(Cuttable hanzai){
マンガの絵を描く;
}
private cut(Cuttable hanzai){
彫刻刀を利用して器用に彫る;
}
private print(Cuttable hanzai){
インクとして、自分の血を使いプリントする;
}
private Cuttable createCuttable(){
return new Potato();
}
}
これで生徒が自由に版材を選択できるようになりました。クラス図を見てみましょう。 ![]() 今回は親クラスの factoryMethod にデフォルトの処理を記述し Wood オブジェクトを返すように記述しましたが、デフォルトの処理を記述せず、抽象メソッドとしておくことも可能ですね。 4.3 FactoryMethod パターンのまとめFactoryMethod パターンの典型的なクラス図は以下の様になります。 ![]() |
![]()
![]()
|