Factory Methodパターン

# Factory Methodパターン
## 0. はじめに
この記事では、Factory Methodパターンについて、以下の3点に分けて説明します。

- 定義と利点
Factory Methodパターンの概要とその利点について説明します。
- 主要なコンポーネント
パターンの主要な構成要素について詳しく解説します。
- 実装例
実際にJavaでFactory Methodパターンを使ったコード例を紹介し、どのように実装するのかを説明します。

## 1. 定義と利点
Factory Methodパターンは、オブジェクトの生成をサブクラスに任せるデザインパターンです。スーパークラスでオブジェクト生成のための「メソッドの枠組み」を定義し、具体的なオブジェクトの生成方法をサブクラスに実装させます。これにより、クライアントコードは具象クラスに依存せず、生成される製品の種類を変更することができます。

このパターンを使用すると、以下のような利点があります。

- コードの再利用性: オブジェクト生成のロジックを共通化でき、再利用性が向上します
- 拡張性: 新たな製品クラスを追加する際に、クライアントコードの変更が不要になるため、拡張が容易です
- 柔軟性: 生成するオブジェクトを動的に決定できるため、柔軟な設計が可能です
- 依存性の低減: クライアントコードは具象クラスを直接知ることなく、インターフェースや抽象クラスに依存するため、依存性が低減します


例えば、異なる種類のドキュメント（PDF、Wordなど）を生成する場合、Factory Methodパターンを使うと、ドキュメントの生成方法をサブクラスに任せ、共通の生成ロジックをスーパークラスに持たせることができます。

Factory Methodパターンは、生成されるオブジェクトの種類が決まっていない、または変更される可能性がある場合に有効です。

## 2. 主要なコンポーネント
Factory Methodパターンは、次の主要なコンポーネントで構成されています。

- **Product（製品）**
  - 生成される製品の共通インタフェースを定義します
- **Creator（作成者）**
  - Factory Methodを定義する抽象クラスを実装します
- **ConcreteProduct（具体的製品）**
  - 実際に生成される製品クラスで、Productインターフェースを実装します
- **ConcreteCreator（具体的作成者）**
  - Factory Methodを具体的に実装するクラスです

## 3. 実装例
実装例ではクラス図とコードの2点に分けて記載します。

### クラス図
Factory Methodパターンのクラス図を示します。

```plantuml
left to right direction
@startuml
abstract class Product {
    +use()
}

abstract class Creator {
    +create(owner: String): Product
    factoryMethod(): Product
}

class ConcreteProduct {
    +use()
}

class ConcreteCreator {
    +factoryMethod(): Product
}

Creator --> Product : "Creates >"
ConcreteProduct --|> Product
ConcreteCreator --|> Creator
ConcreteCreator --> ConcreteProduct : "Creates >"
@enduml

```

### コード
以下はFactory Methodパターンを実際に実行するためのコードです。
```java
// Product.java
// 製品の共通インタフェースを定める
package framework;

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


// Factory.java
// Factory 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);
}


// IDCard.java
// Productインターフェースを実装する
package idcard;
import framework.*;

public class IDCard extends Product {
  private String owner;
  private int serial;
  // コンストラクタがprivateなのでIDCardの生成にはこのpackageを経由しなければならない
  IDCard(String owner, int serial) {
    System.out.println(owner + "(" + serial + ")" + "のカードを作ります。");
    this.owner = owner;
    this.serial = serial;
  }
  public void use() {
    System.out.println(owner + "(" + serial + ")" + "のカードを使います。");
  }
  public String getOwner() {
    return owner;
  }
  public int getSerial() {
    return serial;
  }
}


// IDCardFactory.java
// createProduct, registerProductの中身を実装する
package idcard;
import framework.*;
import java.util.*;

public class IDCardFactory extends Factory {
  private HashMap<Integer, String> database = new HashMap<>();
  private int serial = 100;
  protected Product createProduct(String owner) {
    return new IDCard(owner, serial++);
  }
  protected void registerProduct(Product product) {
    IDCard card = (IDCard)product;
    database.put(new Integer(card.getSerial()), card.getOwner());
  }
  public HashMap<Integer, String> getDatabase() {
    return database;
  }
}


// FactoryTest.java
// 実行処理
import framework.*
import idcard.*;

public class FactoryTest {
  public static void main(String[] args) {
    Factory factory = new IDCardFactory();
    Product card1 = factory.create("田中克弥");
    Product card2 = factory.create("たなかかつや");
    Product card3 = factory.create("TANAKA KATSUYA");
    card1.use();
    card2.use();
    card3.use();
  }
}
```

## 参考文献
この記事は以下の情報を参考にして執筆しました。
[増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88Java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E7%B5%90%E5%9F%8E-%E6%B5%A9/dp/4797327030?ie=UTF8&qid=1454743284&sr=8-1&keywords=java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80)