はじめに
本記事では、ドメイン駆動設計のパターンとして用いられるファクトリについて、初心者向けに解説したものです。
対象読者層
- ドメイン駆動設計初心者
- オブジェクト指向プログラミングに慣れている方
- 複雑なビジネスロジックを扱うシステム開発者
ファクトリの目的
ファクトリは、複雑なオブジェクト生成の責務を専用のクラスに委譲するためのパターンです。
DDDでは、エンティティや値オブジェクト、集約などの生成過程において、以下の目的があります。
生成処理の分離
ドメインオブジェクトの生成ロジックを専用クラスに切り出すことで、ドメインモデル自体をシンプルに保ちます。
ビジネスルールの適用
オブジェクト生成時に、業務上のルール(例:初期状態の整合性チェックや制約の検証)を適用し、不整合な状態を防ぎます。
変更への柔軟な対応
オブジェクト生成ロジックが集中管理されるため、仕様変更があった場合でもファクトリ側を修正すれば済み、保守性が向上します。
また、ファクトリクラスは開発者にとって重要な役割を担うため、専用のパッケージ(例:com.example.factory
)に配置するなど、開発者がその存在に気付けるよう工夫することが望まれます。
サンプルコード
以下は、Javaを例にしたシンプルなファクトリ実装例です。
ここでは、Product
(商品)オブジェクトの生成を、別クラスのProductFactory
で担っています。
Product クラス
package com.example.domain;
public class Product {
private String name;
private double price;
// コンストラクタは直接のインスタンス生成を避けるため、利用には注意が必要です。
// ※完全に隠蔽するためには、同一パッケージ内でのみアクセス可能なパッケージプライベートや
// protected にする方法もありますが、今回はファクトリクラスを別パッケージに配置するため、public としています。
public Product(String name, double price) {
this.name = name;
this.price = price;
}
// getterメソッドなどのドメインロジックを追加可能
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
ProductFactory クラス
package com.example.factory;
import com.example.domain.Product;
public class ProductFactory {
// Productオブジェクトを生成するメソッド
public static Product createProduct(String name, double price) {
// ビジネスルールのチェック(例:価格は0以上でなければならない)
if (price < 0) {
throw new IllegalArgumentException("価格は0以上でなければなりません。");
}
return new Product(name, price);
}
}
この例では、ProductFactory を独立したクラスとして定義し、別パッケージ(com.example.factory)に配置することで、コードベース内でファクトリの存在や役割が明確になり、開発者が利用すべき場所として認識しやすくなっています。
ファクトリの注意事項
ファクトリを利用する際には、いくつかのポイントに注意する必要があります。
必要以上の抽象化を避ける
単純なオブジェクト生成であれば、無理にファクトリを導入する必要はありません。複雑な生成ロジックや複数の依存関係がある場合に使用しましょう。
ビジネスロジックの混在に注意
ファクトリはオブジェクト生成に特化するべきで、他のビジネスロジックを組み込みすぎると責務が曖昧になります。生成に必要なルールのみを実装するよう心がけましょう。
テストの容易さを考慮する
ファクトリ内の処理が複雑になる場合、ユニットテストで生成処理が正しく動作するかを検証することが重要です。特に、例外処理や境界条件のチェックは十分にテストしましょう。
パッケージ設計の工夫
ファクトリクラスは、その役割が明確になるよう、専用のパッケージに配置することが推奨されます。これにより、プロジェクト全体の構造が整理され、他の開発者もここにファクトリクラスがあると直感的に理解できるにすることが大切です。
まとめ
ファクトリパターンは、DDDにおいてドメインオブジェクトの生成責務を明確に分離し、整合性や保守性を向上させるための有用な手法です。
本記事ではドメイン駆動設計入門 として解説しましたが、ドメイン駆動設計ではない開発現場でも有効です。
※元々は、デザインパターン-ファクトリーパターン から来ています。
とはいえ、全てのインスタンス生成でファクトリを採用する必要はありません。
大切なのは、このインスタンス生成は、ファクトリにすることができないか常に考えることです。
常にアンテナを張ることで、複雑なインスタンス生成に対し敏感になることができます。
インスタンスの生成に複雑なルールが存在する場合は、ファクトリを採用してみてください。