mohuneko’s blog

かんばる駆け出しエンジニアのブログです

【Java】Factory Methodパターン【デザインパターン】

駆け出しエンジニアがデザインパターンをもくもく勉強します

 こんな本で勉強しています🌟

目次

Factory Methodパターンについて

Factory Methodパターンとは

サンプルプログラム

  • Factory Methodパターンを使って、身分証明書カードを作成する例を取り上げます
  • 各クラスの役割は以下のようになっています
  • frameworkパッケージは、インスタンス生成の枠組みの役割を担います
  • idcardパッケージは、インスタンス具体的な実装を行います
名前 役割
Product (frameworkパッケージ) useメソッドのみ定義されている抽象クラス
Factory (frameworkパッケージ) createメソッドを実装している抽象クラス
IDCard (idcardパッケージ) useメソッド実装クラス
IDCardFactory (idcardパッケージ) createProduct、registerProductメソッド実装クラス

f:id:mohuNeko:20201227155401p:plain

Productクラス

  • 製品を表現しています
    • ここでの製品とは、"何であれuseできるもの"と、定めています
  • useメソッドの宣言のみ行っていて、具体的な実装は全てサブクラスに任せます
package framework;

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

Factoryクラス

  • Template Method パターンが使われています
    • createメソッドがテンプレートメソッドです
  • 抽象メソッドcreateProduct、registerProduct(製品を作る、登録する)はサブクラスで実装します
    • Factoryクラスは、"createメソッドでProductインスタンスを生成し、createProductして、registerProductする"、という手順で実装されています
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); //製品を登録する
}

IDCardクラス

  • 認証番号をカードを表します
  • Productクラスで宣言されたuseメソッドを実装します
package idcard;
import framework.*;

public class IDCard extends Product {

    private String owner;

    IDCard(String owner) {
        System.out.println(owner + "のカードを作ります。");
        this.owner = owner;
    }

    public void use() {
        System.out.println(owner + "のカードを使います。");
    }

    public String getOwner() {
        return owner;
    }
}

IDCardFactoryクラス

  • Factoryクラスで宣言されたcreateProduct、registerProductメソッドを実装します
  • createProductでIDcardのインスタンスを生成します
  • registerProductでIDcardのownerをownersフィールドに追加しています
package idcard;
import framework.*;
import java.util.*;

public class IDCardFactory extends Factory {

    private List owners = new ArrayList();

    protected Product createProduct(String owner) {
        return new IDCard(owner);
    }

    protected void registerProduct(Product product) {
        owners.add(((IDCard)product).getOwner()); 
    }

    public List getOwners() {
        return owners;  
    }
}

Mainクラスで動作確認

  • createメソッドでIDcardを作って、useメソッドで使います
import framework.*;
import idcard.*;

public class Main {
    public static void main(String[] args) {
        Factory factory = new IDCardFactory();
        Product card1 = factory.create("ナウシカ");
        Product card2 = factory.create("キキ");
        Product card3 = factory.create("千尋");
        card1.use();
        card2.use();
        card3.use();
    }
}

Factory Methodパターンのメリット

  • Creater(Factoryクラス)は、Product(Productクラス)と、インスタンス生成のメソッド(createProduct、registerProductメソッド)を知っていればProduct(IDcard)を生成することができます
  • newによるインスタンス生成を、 インスタンス生成のためのメソッド呼び出しに変えることで、具体的なクラス名(IDCardFactoryクラス)に束縛されません
  • frameworkパッケージは、idcardパッケージに依存していません
  • →他の製品を作りたい場合、import framework.*;した別のパッケージを作れば良いだけで、frameworkパッケージの中身を変更する必要がありません

今日のポイント

  • インスタンスの作り方をスーパークラスで定め、サブクラスで具体的に記述するパターンです
  • インスタンス生成の枠組みと、実際のインスタンス生成のクラスとを分けて考えることができるようになります
  • インスタンス生成の枠組みを記述する(framework)パッケージは、インスタンスの具体的な実装を行うパッケージに依存していません
  • →他のProductを生成したい場合、import framework.*;した別のパッケージを作れば良いだけで、frameworkパッケージの中身を変更する必要がありません

 本日もお疲れ様です😊