ファクトリメソッドとは何か
ファクトリメソッドは
「new の代わりに“生成専用メソッド”を用意して、オブジェクトの作り方をそこに閉じ込める考え方」
です。
普通は new で直接コンストラクタを呼んでオブジェクトを作りますが、
その代わりに
User u = User.ofGuest(); // ← こういう“工場メソッド”を通して作る
Javaのように、「どんな状態で作るか」を表現したメソッドを用意しておき、new を隠してしまうイメージです。
「工場(Factory)」が「作る役」を担当するので、ファクトリメソッドと呼ばれます。
なぜファクトリメソッドを使うのか(重要な目的)
1. 「どう作るか」を隠して、「何を作りたいか」を見せる
コンストラクタだけだと、呼び出し側では「引数の意味」が分かりにくくなることがあります。
User u = new User(true, false, "GUEST");
Javaこれを見ても、true や false が何を表すのか、パッと分かりません。
ファクトリメソッドを使うと、こう書けます。
User u = User.guest();
Java「ゲストユーザを作っているんだな」と、コードを読んだ瞬間に分かります。
内部でどういうフラグや値をセットしているかは、guest() の中に隠してしまいます。
2. 作るクラスを後から差し替えやすくする
インターフェースを返すファクトリメソッドにしておくと、
「どの実装クラスを作るか」をメソッドの中で決められます。
呼び出し側はインターフェース型だけを見ておけばよく、
実装クラスを変えても呼び出し側のコードは変えずに済みます。
3. 複雑な生成ロジックを一箇所にまとめる
「引数の検証」「デフォルト値の補完」「同じものを使い回す」などのロジックを
ファクトリメソッドに集約しておくと、
呼び出し側では余計なことを考えずに「作ってもらう」だけでよくなります。
シンプルな例:状態を分かりやすくするファクトリメソッド
悪い例:コンストラクタだけで頑張る
final class User {
private final boolean guest;
private final String name;
User(boolean guest, String name) {
this.guest = guest;
this.name = name;
}
boolean isGuest() { return guest; }
String name() { return name; }
}
Javaこれを使う側はこう書きます。
User u1 = new User(true, "GUEST");
User u2 = new User(false, "Taro");
Javatrue / false の意味も "GUEST" の意味も、呼ばれる側の知識を知らないと分かりません。
「ここの true は“ゲスト”って意味で…」と、呼び出し側が内部仕様を知っている必要があります。
良い例:ファクトリメソッドで「意図」を表現する
final class User {
private final boolean guest;
private final String name;
private User(boolean guest, String name) { // コンストラクタは隠す
this.guest = guest;
this.name = name;
}
static User guest() { // ゲスト専用の工場
return new User(true, "GUEST");
}
static User named(String name) { // 名前付きユーザ専用の工場
return new User(false, name);
}
boolean isGuest() { return guest; }
String name() { return name; }
}
Java呼び出し側はこう書けます。
User u1 = User.guest();
User u2 = User.named("Taro");
Javaguest() や named(String) という名前で、「どういう状態の User を作りたいのか」がコードにハッキリ表れます。
コンストラクタは private にして、外から new させないようにしておくのがポイントです。
これで、「User の作られ方」をすべてクラスの中に閉じ込められます。
インターフェース+ファクトリメソッド(実装を隠すパターン)
実装クラスを隠したいときのファクトリメソッド
インターフェースを返すファクトリメソッドにすると、「どの実装クラスか」を隠せます。
interface Formatter {
String format(String raw);
}
Javaこのインターフェースの実装として、いくつかクラスがあるとします。
final class UpperFormatter implements Formatter {
@Override
public String format(String raw) {
return raw == null ? "" : raw.toUpperCase();
}
}
final class LowerFormatter implements Formatter {
@Override
public String format(String raw) {
return raw == null ? "" : raw.toLowerCase();
}
}
Java普通に書くと、呼び出し側は「どのクラスを new するか」を知っている必要があります。
Formatter f = new UpperFormatter();
Javaこれをファクトリメソッドで隠します。
final class Formatters {
private Formatters() {} // インスタンス化させない
static Formatter upper() {
return new UpperFormatter();
}
static Formatter lower() {
return new LowerFormatter();
}
}
Java呼び出し側はこう書けます。
Formatter f1 = Formatters.upper();
Formatter f2 = Formatters.lower();
Java将来、「UpperFormatter の実装を変えたい」「別のクラスに差し替えたい」となっても、
修正すべき場所は Formatters.upper() の中身だけです。
呼び出し側は「upper なフォーマッタが欲しい」としか言っていないので、
具体クラスが何であろうと関係ありません。
これが「実装を隠す」という効果です。
生成ロジックが複雑な場合のファクトリメソッド(深掘り)
検証や変換をまとめて行う
例えば「文字列から金額オブジェクトを作る」ケースを考えます。
final class Money {
private final int amount;
Money(int amount) {
if (amount < 0) throw new IllegalArgumentException("minus");
this.amount = amount;
}
int amount() { return amount; }
}
Java呼び出し側が文字列から作ろうとすると、こうなります。
String raw = "1000";
int v = Integer.parseInt(raw);
Money m = new Money(v);
Javaこのパターンをあちこちで繰り返すと、
変換ロジックとエラーハンドリングが散らばってしまいます。
ファクトリメソッドにまとめてしまいましょう。
final class Money {
private final int amount;
private Money(int amount) {
if (amount < 0) throw new IllegalArgumentException("minus");
this.amount = amount;
}
static Money of(int amount) {
return new Money(amount);
}
static Money parse(String raw) { // 文字列から作る工場
if (raw == null || raw.isBlank()) {
throw new IllegalArgumentException("blank");
}
int v = Integer.parseInt(raw.trim());
return new Money(v);
}
int amount() { return amount; }
}
Java呼び出し側はこう書くだけです。
Money m1 = Money.of(1000);
Money m2 = Money.parse(" 2000 ");
Javaparse の中で
文字列の null チェック
trim
数値変換
0 未満のチェック
といった「生成に関する面倒ごと」を全部面倒見ています。
呼び出し側は「Money を作ってもらう」だけでよくなります。
生成ロジックが複雑なほど、ファクトリメソッドの価値は上がります。
ファクトリメソッドとコンストラクタの役割分担(重要な考え方)
コンストラクタは「最低限」、ファクトリメソッドで「表現力」
コンストラクタは「内部状態を成立させる最低限の処理」に絞り、
「どのパターンで作るか」「どう検証するか」「どう変換するか」は
ファクトリメソッド側に寄せる、と考えると設計が綺麗になります。
コンストラクタの役割は、「引数として渡された値をフィールドに正しくセットし、不変条件を守ること」。
ファクトリメソッドの役割は、「どの値を渡すか決めたり、元の入力から変換したりすること」。
その結果、
コンストラクタは private または package-private にする
外からは基本的にファクトリメソッド経由でしか作らせない
というスタイルが自然に出てきます。
まとめ:ファクトリメソッドを設計の武器にする
ファクトリメソッドの本質は、「作り方を隠し、意図を名前で表し、生成ロジックを一箇所に集約する」ことです。
new をどこでも気軽に呼ぶのではなく、
この状態のインスタンスを作りたい
この入力から安全に変換して作りたい
このインターフェースの実装が欲しいが、どのクラスかは隠したい
といったときに、静的メソッド(of, from, parse, guest, named など)を用意して、
「工場」としての責任をそこに持たせます。
