It's interesting.

いつまでも中二病。

Factory Methodの最低限押さえておくべきポイントとは?

この記事は、GoFのデザインパターン23個のうちのFactory Methodについて解説したものです。

Factory Methodパターン以外の解説記事はこちらからご覧ください。

Factory Methodとは?

以前、以下の記事でTemplate Methodパターンについて解説しました。
www.macky-studio.com

Template Methodパターンは処理の雛形となるテンプレートを用意しておき、具体的な処理内容はサブクラスが決めるというものでした。
このパターンをインスタンスの生成に応用したものがFactory Methodパターンです。
インスタンス生成時にメソッド1を行った後にメソッド2を必ず行うという流れは決まっているけれども、メソッド1及びメソッド2の内容はサブクラスで自由に決めていいよ!というパターンです。(メソッドの数は例として2つにしただけで、この数に決まりはありません)

Factory Methodを使ったプログラム例

例として、車を作る工場を考えます。
インスタンスを生成するフレームワーク側(抽象クラス)と実際の処理を決める具象クラスに別れている点がポイントです。

Product.java
フレームワーク側の抽象クラス。

package framework;

public abstract class Product {
    public abstract void use();
}

Factory.java
フレームワーク側の抽象クラス。
Productインスタンスを生成するTemplate Methodを用意しています。
「製品を生成し、登録する」という枠組みだけが決まっています。

package framework;

public abstract class Factory {
    public final Product create(String owner) {
        Product p = createProduct(owner);
        registerProduct(p);
        return p;
    }
    protected abstract Product createProduct(String owner);
    protected abstract void registerProduct(Product product);
}

Car.java
Productクラスを実装したクラス。

package card;
import framework.*;

public class Car extends Product {
    private String owner;
    private int number;
    
    Car(String owner, int number) {
        System.out.println(owner + "の車を作ります。");
        this.owner = owner;
        this.number = number;
    }
    public void use() {
        System.out.println(owner + "の車を運転します。");
    }
    public String getOwner() {
        return owner;
    }
    public int getNumber() {
        return number;
    }
}

CarFactory.java
Factoryクラスを実装したクラス。

package card;
import framework.*;
import java.util.*;

public class CarFactory extends Factory {
    private HashMap database = new HashMap();
    private int number = 0;
    
    protected synchronized Product createProduct(String owner) {
        return new Car(owner, number++);
    }
    protected void registerProduct(Product product) {
        Car car = (Car)product;
        database.put(new Integer(car.getNumber()), car.getOwner());
    }
    public HashMap getDatabase() {
        return database;
    }
}

Main.java
作成したプログラムの動作を確かめるプログラムです。

public class Main {
    public static void main(String[] args) throws Exception {
        Factory factory = new CarFactory();
        Product car1 = factory.create("Tom");
        Product car2 = factory.create("Mike");
        car1.use();
        car2.use();
    }
}

実行結果

Tomの車を作ります。
Mikeの車を作ります。
Tomの車を運転します。
Mikeの車を運転します。

最低限押さえておくべきポイント

先程も言いましたが、インスタンスを生成する流れを定義するフレームワーク側とそれを利用する側に分かれている点がポイントです。
そうすることで、具体的なクラス名はサブクラスで決めることができ、別の製品を作る場合にもフレームワークを利用して簡単にインスタンスを生成することができます。

まとめ

Factory Methodパターンを用いることで、インスタンスの生成方法をフレームワークとして提供できるため、プログラムの再利用性が高まります。
複数のサービスや製品を展開していて、会員情報の作成プロセスが共通している場合や、製品の作成プロセスが共通している場合によく使われるのかなぁと思いました!
ただ、実際にパターンを適用するには練習が必要ですね。。。

参考書籍

入門とだけあって、非常に分かりやすいです。
Javaの基本的な知識があれば割とすらすら読み進められるのでおすすめです。