Javaのファクトリーパターン:オブジェクト生成の効率化
ファクトリーデザインパターンの意図
Javaのファクトリーデザインパターンは、オブジェクトを作成するためのインターフェースを定義しますが、サブクラスが作成されるオブジェクトのタイプを変更できるようにする生成パターンです。このパターンは、コードベースの柔軟性とスケーラビリティを促進します。
ファクトリーパターンの詳細な説明と実世界の例
実世界の例
ファクトリーデザインパターンを使用してさまざまな種類のケーキが作られるパン屋のシナリオを想像してください。パン屋の
CakeFactory
は作成プロセスを処理し、コアなケーキ作りプロセスを変更せずに新しいケーキの種類を簡単に追加できるようにします。CakeFactory
は、チョコレートケーキ、バニラケーキ、ストロベリーケーキなど、さまざまな種類のケーキを作ることができます。パン屋のスタッフが各種類のケーキの材料を手動で選択し、特定のレシピに従うのではなく、CakeFactory
を使用してプロセスを処理します。顧客は単にケーキの種類を要求すると、CakeFactory
は使用する適切な材料とレシピを決定し、特定の種類のケーキを作成します。この設定により、パン屋はコアなケーキ作りプロセスを変更せずに新しいケーキの種類を簡単に追加でき、柔軟性とスケーラビリティを促進できます。
Wikipediaによると
ファクトリーとは、他のオブジェクトを作成するためのオブジェクトです。正式には、ファクトリーとは、さまざまなプロトタイプまたはクラスのオブジェクトを返す関数またはメソッドです。
Javaでのファクトリーパターンのプログラム例
錬金術師がコインを製造しようとしていると想像してください。錬金術師は、金貨と銅貨の両方を作成でき、既存のソースコードを変更せずにそれらを切り替えることができる必要があります。ファクトリーパターンは、関連するパラメーターを指定して呼び出すことができる静的な構築メソッドを提供することにより、これを可能にします。
Javaでは、インターフェースCoin
とその実装であるGoldCoin
とCopperCoin
を定義することにより、ファクトリーパターンを実装できます。CoinFactory
クラスは、タイプに基づいてコインオブジェクトを作成する静的メソッドgetCoin
を提供します。
public interface Coin {
String getDescription();
}
public class GoldCoin implements Coin {
static final String DESCRIPTION = "This is a gold coin.";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class CopperCoin implements Coin {
static final String DESCRIPTION = "This is a copper coin.";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
以下の列挙は、サポートするコインの種類(GoldCoin
とCopperCoin
)を表します。
@RequiredArgsConstructor
@Getter
public enum CoinType {
COPPER(CopperCoin::new),
GOLD(GoldCoin::new);
private final Supplier<Coin> constructor;
}
次に、ファクトリークラスCoinFactory
にカプセル化されたコインオブジェクトを作成する静的メソッドgetCoin
があります。
public class CoinFactory {
public static Coin getCoin(CoinType type) {
return type.getConstructor().get();
}
}
これで、クライアントコードで、ファクトリークラスを使用してさまざまな種類のコインを生成できます。
public static void main(String[] args) {
LOGGER.info("The alchemist begins his work.");
var coin1 = CoinFactory.getCoin(CoinType.COPPER);
var coin2 = CoinFactory.getCoin(CoinType.GOLD);
LOGGER.info(coin1.getDescription());
LOGGER.info(coin2.getDescription());
}
プログラム出力
06:19:53.530 [main] INFO com.iluwatar.factory.App -- The alchemist begins his work.
06:19:53.533 [main] INFO com.iluwatar.factory.App -- This is a copper coin.
06:19:53.533 [main] INFO com.iluwatar.factory.App -- This is a gold coin.
Javaでファクトリーパターンを使用する場合
- Javaでファクトリーデザインパターンを使用するのは、クラスが作成する必要があるオブジェクトの正確なタイプと依存関係を事前に知らない場合です。
- メソッドが共通のスーパークラスを共有するいくつかの可能なクラスのいずれかを返し、どのオブジェクトを作成するかというロジックをカプセル化したい場合。
- このパターンは、フレームワークまたはライブラリを設計する際に、具象クラスのタイプから最高の柔軟性と分離を提供するために一般的に使用されます。
Javaでのファクトリーパターンの実世界の応用例
- java.util.Calendar#getInstance()
- java.util.ResourceBundle#getBundle()
- java.text.NumberFormat#getInstance()
- java.nio.charset.Charset#forName()
- java.net.URLStreamHandlerFactory#createURLStreamHandler(String)(プロトコルに応じて異なるシングルトンオブジェクトを返します)
- java.util.EnumSet#of()
- javax.xml.bind.JAXBContext#createMarshaller()およびその他の類似メソッド。
- JavaFXは、ユーザー環境の仕様に合わせて調整されたさまざまなUIコントロールを作成するためにファクトリーパターンを使用します。
ファクトリーパターンの利点とトレードオフ
利点
- Javaアプリケーションにファクトリーパターンを実装すると、実装とその使用するクラス間の結合が削減されます。
- システムが既存のコードを変更せずに新しいタイプを導入できるため、オープン/クローズド原則をサポートします。
トレードオフ
- 複数の追加クラスが導入されるため、コードがより複雑になる可能性があります。
- オブジェクト作成の基本的な複雑さが低い場合、または不要な場合は、過剰に使用するとコードの可読性が低下する可能性があります。
関連するJavaデザインパターン
- 抽象ファクトリー:製品のグループを扱う一種のファクトリーと見なすことができます。
- シングルトン:クラスにインスタンスが1つしかないことを保証するために、ファクトリーと組み合わせて使用されることがよくあります。
- ビルダー:ファクトリーがインスタンス化を管理する方法と同様に、複雑なオブジェクトの構築をその表現から分離します。
- ファクトリーキット:分離されたビルダーインターフェースとファクトリーインターフェースを備えたイミュータブルコンテンツのファクトリーです。