한국어 | English | 日本語
Webアプリケーションエンジニア (経験8.8年)
技術・開発
engineering
ウェブフロントエンドと バックエンド開発を扱います

2. ファクトリ「メソッド」パターン & 「抽象」ファクトリパターン

開発を進めていると、「状態に応じて異なるフロー」を処理しなければならない場面に遭遇することがあります。単に「はい/いいえ」のような単一の状態であれば`if`文で十分ですが、複数の状態がある場合は`if-else`または`switch`を使用するでしょう。しかし、「異なるフロー」に該当するロジックが複雑になると、`if-else`のブロックが100行を超えるコードになることも珍しくありません。これは果たして再利用性が高いと言えるでしょうか?コードが読みにくいだけでなく、その100行の中に繰り返し現れるロジックも間違いなく存在するはずです。「異なるロジック」と「共通ロジック」を分離し、「異なるロジック」の部分は状態に応じて異なる実装を返したり、実装を作成したりするパターンが必要となります。
状態に応じた実装を返すこと、そしてその実装を返す主体が関数である場合、これをファクトリメソッドと呼び、そのデザイン原則を「ファクトリメソッドパターン」と称します。一方、ファクトリメソッドから「ファクトリ」としての役割を切り離し、メソッドが単に汎用的なカテゴリオブジェクトを返すだけに留め、状況に応じた具体的な実装を抽象ファクトリインターフェースに委譲したものが「抽象ファクトリパターン」です。要するに、状況に応じた実装(ファクトリロジック)をメソッドが行うのがファクトリ「メソッド」パターンであり、インターフェースがその責任を負うのが「抽象」ファクトリパターンなのです。

「ファクトリ」とは何か?

ファクトリとは、単純に自動販売機を考えると分かりやすいです。「飲み物」の自動販売機からは「飲み物」が出てきて、「お菓子」の自動販売機からは「お菓子」が出てきます。自動販売機(VendingMachine)と商品(Product)はどちらもインターフェースで定義されているため、「商品(Product)」を飲み物として実装すれば、「自動販売機(VendingMachine)」は飲み物自動販売機として実装すれば良いのです。

	VendingMachine machine;
	Product product;
	VendingMachine machine = new BeverageVendingMachine();
	Product product = machine.get();

ファクトリとは、上記のように状況に応じて実装することを指します。

「ファクトリメソッド」とは何か?

ファクトリメソッドは、文字通り状況に応じて実装するファクトリの役割を担うメソッドです。どのようなProductであるかに応じてProduct実装を返す関数で、上記の例ではmachine.get()に該当します。

ファクトリメソッドパターン

ファクトリメソッドパターンは、インターフェース内に定義されている「ファクトリメソッド」を、状況に応じた実装オブジェクトを返すように、状況に合わせて具体的な「実装ファクトリメソッド」を作成するものです。これを使用することで得られるメリットを見てみましょう。

class VendingMachine {
	public Product get(String type) {
		if (type == "beverage") {
			return new Beverage();
		} else if (type == "snack") {
			return new Snack();
		}
	}
}
	VendingMachine machine = new VendingMachine();
	Product product = machine.get('beverage');
interface VendingMachine {
	public Product get();
}

class BeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new Beverage();
	}
}

class SnackVendingMachine implements VendingMachine {
	public Product get() {
		return new Snack();
	}
}
	VendingMachine machine = new BeverageVendingMachine();
	Product product = machine.get();

VendingMachineインターフェース内のファクトリメソッドを、状況に合わせてどのような実装を返すか実装すれば良いだけです。もう使用しない状況の実装クラスは単に削除すればよく、追加の状況に応じた処理が必要な場合はクラスを作成するだけで済みます。

抽象ファクトリパターン

ところで、飲み物の種類がますます多様になると仮定しましょう。ファクトリメソッドパターンを使用した場合、次のように毎回クラスが生成されますが、このままで本当に良いのでしょうか?どんなに多くの種類の飲み物が生まれても、結局「飲み物(Beverage)」という分類は変わりません。ただ中身が変わるだけです。

interface VendingMachine {
	public Product get();
}

class FruitBeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new FruitBeverage();
	}
}

class SparklingBeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new SparklingBeverage();
	}
}

class TeaBeverageVendingMachine implements VendingMachine {
	public Product get() {
		return new TeaBeverage();
	}
}

...

FruitBeverageSparklingBeverageTeaBeverageはすべて飲み物という分類に含まれ、実際に3つの内部クラスのロジックはわずかな違いしかなく、ほとんどが同じでしょう。Beverageという汎用的な飲み物クラスを作成し、その中に入れる材料だけを変えれば良いはずです。そうすることで、...Beverageクラスが量産されるという重複を以下のように解決します。

interface VendingMachine {
	Maker maker;
	public Product get() {
		return new Beverage(maker);
	}
}

class FruitBeverageVendingMachine implements VendingMachine {
	Maker maker = new FruitBeverageMaker();
}

class SparklingBeverageVendingMachine implements VendingMachine {
	Maker maker = new SparklingBeverageMaker();
}

class TeaBeverageVendingMachine implements VendingMachine {
	Maker maker = new TeaBeverageMaker();
}

...

「ファクトリメソッドパターン」はファクトリ「メソッド」が__状況に応じた実装オブジェクト__を返すのに対し、「抽象ファクトリパターン」はメソッドはカテゴリオブジェクトを単に返すだけで、__状況に応じた詳細な実装__は「抽象」ファクトリインターフェースに委譲したものです。

しかし、...Beverageクラスが量産されるのと...BeverageMakerクラスが量産されるのは、実質的に同じことではないでしょうか?はい、同じです。では、なぜわざわざ状況に応じた実装の責任を抽象ファクトリインターフェースに委譲したのでしょうか?

VendingMachineは製品を提供する役割だけを持ち、製品生産に関する責任はBeverageMakerが分担するためです。

2. ファクトリ「メソッド」パターン & 「抽象」ファクトリパターン
Author
Aaron
Posted on
Licensed Under
CC BY-NC-SA 4.0
CC BY-NC-SA 4.0
同じカテゴリーの関連記事
最新記事
LLMフィルターが奪う会話の筋肉とコミュニケーション様式
会話における無礼さを濾過し、洗練された回答を生成するLLMツールが日常化した現代において、私たちは本当に思慮深い会話をしているのだろうか?リアルタイムのコミュニケーションにおける数多くの失敗を通じて磨かれるべき会話能力が、外部ツールに依存することで退化している現象と、それがもたらす社会的な不安や世代間の行動様式の変化について考察する。
シニア採用における年俸交渉の最適なタイミングと戦略
年俸交渉は単なる数字の交換ではなく、心理的な駆け引きとタイミングが重要です。本稿では、企業側にとって、候補者が計算的な態度を取りがちな最終合格後よりも、採用プロセスの初期段階から段階的に交渉を進めることが、なぜより効率的であり、率直な情報の共有に繋がるのかを考察します。
法治主義の限界と人間の多様性
全ての人間の行為を単一の法体系で規制できるという信念は、傲慢であるかもしれない。この記事は、中世の階層的な統制から脱却し、現代の無限の自由を手に入れた人類が直面する法治主義の逆説と、多様性という名のもとに深化する社会的強制力と他者への悪魔化現象を鋭く分析する。
토스트 예시 메세지