Java
初心者
デザインパターン
初心者エンジニア

Java初心者のデザインパターン(Factory Methodパターン)

はじめに

Qiita初投稿になります。
Javaデザインパターン徹底攻略に出てくるGoFデザインパターン23種類を頑張ってまとめていきたいと思います。
内容に対しての誤りはもちろん、それ以外についてもご指摘いただけると幸いです。

Factory Method パターンとは

Factory Methodパターンは、あるサブクラスと別のサブクラスをペアにして使いたいといった場合に使用するデザインパターン。
例えば、ある人物(鈴木さん)の属性(名前、年齢、住所、部屋の階数)を通知する機能を作成する際に、人物に関する情報(名前・年齢)と場所に関する情報(住所・部屋の階数)を分け、「名前」と「年齢」を通知する抽象クラスClassA、「住所」と「部屋の階数」を通知する抽象クラスClassBを以下のように作るとします。

ClassA.java
abstract class ClassA{
     abstract String getName();
     abstract int    getAge();
}
ClassB.java
abstract class ClassB{
     abstract String getAddress();
     abstract int getFloor();
}

この2つの抽象クラスを継承することで、それぞれの人物の情報を通知するクラスを作成できるようになります
例:鈴木さんの情報を通知するクラス

ClassA1.java
class ClassA1 extends ClassA{
    String getName(){return "Suzuki";}
    int    getAge(){return 28;}
}
ClassB1.java
class ClassB1 extends ClassB{
     String getAddress(){return "Chiba";}
     int    getFloor(){return 1;}
}

例:宮尾さんの情報を通知するクラス

ClassA2.java
class ClassA2 extends ClassA{
     String getName(){return "Miyao";}
     int    getAge(){return 23;}
}
ClassB2.java
class ClassB2 extends ClassB{
     String getAddress(){return "Tokyo";}
     int    getFloor(){return 2;}
}

このように抽象クラスを継承したサブクラスを増やしていくことで、いろんな人の情報を取り出せるように拡張していくことができます。しかし、サブクラスが増えてくると、ペアで使用するべきサブクラス(上記の例では、ClassA1とClassB1・ClassA2とClassB2)を間違わないように実装しなければなりません。

このような場合に使用するのが、Factory Methodパターンです。すなわち、ペアにして使用しなければならないサブクラスのオブジェクトを生成する際に、各サブクラスのコンストラクタを直接呼ぶのではなく、ペアの一方はコンストラクタを呼んで生成し、もう一方は「生成済みのペアの片方のオブジェクト」に生成してもらうようにするのです。そのためには「ペアになるサブクラスのオブジェクトを生成するメソッド」(ファクトリメソッド)を一方のクラスに用意します。
このように、ペアとなるオブジェクトを生成するメソッドを用意するパターンがFactory Methodパターンです。Factory Methodパターンを使用すればペアとなるオブジェクトを生成するメソッドを呼び出すだけで良いため、ペアで使用するサブクラスの組み合わせを実装者が意識する必要がありません。(上記の例では、ClassA1のペアがClassB1であることを知る必要がなくなります。)

今回の例にFactory Methodパターンを適用すると以下のようになります。

ClassA.java
abstract class ClassA{
      abstract String getName();
      abstract int    getAge();
      abstract ClassB createClassB();//ファクトリメソッド
}

ClassAにペアとなるClassBのサブクラスを1つ生成して返すファクトリメソッド createClassB()を追加しました。ファクトリメソッドの実装は以下のようにサブクラスで定義します。

ClassA1.java
class ClassA1 extends ClassA{
     String getName(){return "suzuki";}
     int    getAge(){return 20;}
     ClassB1 createClassB1(){return new ClassB1();}
}
ClassA2.java
class ClassA2 extends ClassA{
     String getName(){return "Miyao";}
     int    getAge(){return 23;}
     ClassB2 createClassB2(){return new ClassB2();}
}

ClassA1はペアとなるClassB1のオブジェクトを生成し、ClassA2はペアとなるClassB2のオブジェクトを生成します。このように片方のクラスがペアとなるクラスのオブジェクト生成を担うことで、実装者はClassA1・ClassA2を使用する際にペアとなるサブクラスを意識する必要がなくなります。

作成したクラスを使用するメインクラスは以下のようになります。

Main.java
class Main{
   public static void main(String args...){
       ClassA classA = new ClassA2();

       ClassB classB = classA.createClassB();

       System.out.println(classA.getName());   // Miyao
       System.out.println(classA.getAge());    // 23
       System.out.println(classB.getAddress());// Tokyo
       System.out.println(classB.getFloor());  // 2
   }
}

実装者はcreateClassB()を呼び出すだけで、ClassA2のペアとなるサブクラスがClassB2である事を知る必要がありません。