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パターンのクラス図を示します。
コード
以下はFactory Methodパターンを実際に実行するためのコードです。
// 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言語で学ぶデザインパターン入門