|
| 1 | +--- |
| 2 | +title: GoFデザインパターン - ファクトリメソッド編 |
| 3 | +date: 2026-01-27 |
| 4 | +category: Coding |
| 5 | +description: GoFコレクションにおけるファクトリメソッドパターン実践ガイド:概念、使いどころ、C++/Python の実装例、注意点と出典を実用的に解説します |
| 6 | +tags: [Coding, DesignPattern] |
| 7 | +recommended: true |
| 8 | +thumbnail: assets/img/ogp.png |
| 9 | +--- |
| 10 | + |
| 11 | +こんにちは!パン君です。 |
| 12 | + |
| 13 | +今回は GoF(Gang of Four)のデザインパターンのファクトリメソッド編になります。 |
| 14 | +サンプルコード(C++)、作り方、使うタイミング、注意点などを含めて実用的に解説します。 |
| 15 | + |
| 16 | +## はじめに |
| 17 | + |
| 18 | +ファクトリメソッドはサブクラスが生成する具体的なクラスを決定するためのメソッドを提供するデザインパターンです。 |
| 19 | +言い換えると、オブジェクト生成の責務をサブクラスに委譲することで、クライアントコードは具体的な実装に依存せずに動作できます。 |
| 20 | + |
| 21 | +Wikipedia の定義は下記です |
| 22 | + |
| 23 | +> "オブジェクト指向プログラミングにおいて、ファクトリメソッドパターンは作成されるオブジェクトの正確なクラスを指定せずにオブジェクトを作成する問題に対処するためにファクトリメソッドを使用する生成パターンである。" |
| 24 | +> (出典: [https://en.wikipedia.org/wiki/Factory_method_pattern](https://en.wikipedia.org/wiki/Factory_method_pattern)) |
| 25 | +
|
| 26 | +上記はファクトリメソッドの本質を端的に示しています |
| 27 | +生成の「いつ」「どのクラスを」決めるかを実行時の文脈やサブクラスの実装に委ねる、ということです。 |
| 28 | + |
| 29 | +## 構造(要素) |
| 30 | + |
| 31 | +典型的な構成は次の通りです。 |
| 32 | + |
| 33 | +- `Product`(抽象製品):クライアントが扱う共通インターフェース |
| 34 | +- `ConcreteProduct`:具体的な製品の実装 |
| 35 | +- `Creator`(抽象作成者):`FactoryMethod()` を宣言(場合によっては一部の共通処理も持つ)。 |
| 36 | +- `ConcreteCreator`:`FactoryMethod()` をオーバーライドし、具体的な `ConcreteProduct` を生成して返す。 |
| 37 | + |
| 38 | +`Creator` は生成された `Product` を使って何らかの処理を行い、クライアントは `Creator` の操作だけを利用します。 |
| 39 | + |
| 40 | +```mermaid |
| 41 | +classDiagram |
| 42 | + class Product { |
| 43 | + <<interface>> |
| 44 | + +Use() |
| 45 | + } |
| 46 | +
|
| 47 | + class ConcreteProductA |
| 48 | + class ConcreteProductB |
| 49 | + Product <|-- ConcreteProductA |
| 50 | + Product <|-- ConcreteProductB |
| 51 | +
|
| 52 | + class Creator { |
| 53 | + <<abstract>> |
| 54 | + +FactoryMethod() Product |
| 55 | + +Operation() |
| 56 | + } |
| 57 | +
|
| 58 | + class ConcreteCreatorA |
| 59 | + class ConcreteCreatorB |
| 60 | + Creator <|-- ConcreteCreatorA |
| 61 | + Creator <|-- ConcreteCreatorB |
| 62 | +
|
| 63 | + ConcreteCreatorA ..> ConcreteProductA : creates |
| 64 | + ConcreteCreatorB ..> ConcreteProductB : creates |
| 65 | +``` |
| 66 | + |
| 67 | +## 短いメリット / デメリット |
| 68 | + |
| 69 | +メリット: |
| 70 | +- 生成ロジックと利用ロジックを分離できる。 |
| 71 | +- 新しい `ConcreteProduct` を追加しても既存のクライアントコードを変更せずに済む(拡張に対して開かれている)。 |
| 72 | +- テスト時に `Creator` を差し替えることで生成される型を制御できる(モック生成など)。 |
| 73 | + |
| 74 | +デメリット: |
| 75 | +- サブクラスが増えるとクラス数が増える(サブクラス増加による管理コスト)。 |
| 76 | +- 単純なケースでは過剰な抽象化になることがある(過剰設計)。 |
| 77 | +- 生成の決定が分散することで設計を追うのが難しくなる場合がある。 |
| 78 | + |
| 79 | +## 「シンプルファクトリ」「抽象ファクトリ」との違い(整理) |
| 80 | + |
| 81 | +- `Simple Factory`: ファクトリ関数/クラスが条件分岐で具体クラスを返す単純な実装。GoF の正式なパターンではないがよく使われる。 |
| 82 | +- `Factory Method`: サブクラス化により生成クラスを決定する。生成ロジックはオブジェクト指向の多態性で拡張される。 |
| 83 | +- `Abstract Factory`: 関連する複数のオブジェクト群(製品族)を生成するためのインターフェースを提供する。製品群の整合性を保つ。 |
| 84 | + |
| 85 | +選択基準の目安: |
| 86 | +- 単一の製品を生成し、サブクラスごとに生成方法を変えたい → `Factory Method` |
| 87 | +- 関連する複数の製品群(例:UI ウィジェットのテーマ一式)をまとめて切り替えたい → `Abstract Factory` |
| 88 | + |
| 89 | +## 実装例:C++(典型) |
| 90 | + |
| 91 | +以下は最小限の C++ サンプルです。`Creator` が `FactoryMethod()` を宣言しており、`ConcreteCreator` が具体生成を行います。 |
| 92 | + |
| 93 | +```cpp |
| 94 | +// Product.h |
| 95 | +class Product { |
| 96 | +public: |
| 97 | + virtual ~Product() = default; |
| 98 | + virtual const char* Use() const = 0; |
| 99 | +}; |
| 100 | + |
| 101 | +// ConcreteProductA.h |
| 102 | +#include "Product.h" |
| 103 | +class ConcreteProductA : public Product { |
| 104 | +public: |
| 105 | + const char* Use() const override { return "ConcreteProductA"; } |
| 106 | +}; |
| 107 | + |
| 108 | +// ConcreteProductB.h |
| 109 | +#include "Product.h" |
| 110 | +class ConcreteProductB : public Product { |
| 111 | +public: |
| 112 | + const char* Use() const override { return "ConcreteProductB"; } |
| 113 | +}; |
| 114 | + |
| 115 | +// Creator.h |
| 116 | +#include <memory> |
| 117 | +class Creator { |
| 118 | +public: |
| 119 | + virtual ~Creator() = default; |
| 120 | + // Factory Method(生成をサブクラスに委譲) |
| 121 | + virtual std::unique_ptr<Product> FactoryMethod() const = 0; |
| 122 | + |
| 123 | + // Creator は生成された Product を使う共通処理を持てる |
| 124 | + std::string Operation() const { |
| 125 | + auto product = FactoryMethod(); |
| 126 | + return std::string("Creator uses ") + product->Use(); |
| 127 | + } |
| 128 | +}; |
| 129 | + |
| 130 | +// ConcreteCreatorA.h |
| 131 | +#include "Creator.h" |
| 132 | +#include "ConcreteProductA.h" |
| 133 | +class ConcreteCreatorA : public Creator { |
| 134 | +public: |
| 135 | + std::unique_ptr<Product> FactoryMethod() const override { |
| 136 | + return std::make_unique<ConcreteProductA>(); |
| 137 | + } |
| 138 | +}; |
| 139 | + |
| 140 | +// ConcreteCreatorB.h |
| 141 | +#include "Creator.h" |
| 142 | +#include "ConcreteProductB.h" |
| 143 | +class ConcreteCreatorB : public Creator { |
| 144 | +public: |
| 145 | + std::unique_ptr<Product> FactoryMethod() const override { |
| 146 | + return std::make_unique<ConcreteProductB>(); |
| 147 | + } |
| 148 | +}; |
| 149 | + |
| 150 | +// main.cpp (利用例) |
| 151 | +#include <iostream> |
| 152 | +int main() { |
| 153 | + ConcreteCreatorA a; |
| 154 | + ConcreteCreatorB b; |
| 155 | + std::cout << a.Operation() << "\n"; // Creator uses ConcreteProductA |
| 156 | + std::cout << b.Operation() << "\n"; // Creator uses ConcreteProductB |
| 157 | +} |
| 158 | +``` |
| 159 | +
|
| 160 | +この実装のポイントは、`Creator` の `Operation()` は具体的な `Product` のクラスを知らずに動作する点です。`ConcreteCreator` を差し替えるだけで動作が変わります。 |
| 161 | +
|
| 162 | +## 実装例:Python(簡潔) |
| 163 | +
|
| 164 | +動的言語では実装がさらに簡潔になります。サブクラスで `factory_method` をオーバーライドします。 |
| 165 | +
|
| 166 | +```python |
| 167 | +from abc import ABC, abstractmethod |
| 168 | +
|
| 169 | +class Product(ABC): |
| 170 | + @abstractmethod |
| 171 | + def use(self) -> str: |
| 172 | + pass |
| 173 | +
|
| 174 | +class ConcreteProductA(Product): |
| 175 | + def use(self) -> str: |
| 176 | + return "ConcreteProductA" |
| 177 | +
|
| 178 | +class ConcreteProductB(Product): |
| 179 | + def use(self) -> str: |
| 180 | + return "ConcreteProductB" |
| 181 | +
|
| 182 | +class Creator(ABC): |
| 183 | + @abstractmethod |
| 184 | + def factory_method(self) -> Product: |
| 185 | + pass |
| 186 | +
|
| 187 | + def operation(self) -> str: |
| 188 | + product = self.factory_method() |
| 189 | + return f"Creator uses {product.use()}" |
| 190 | +
|
| 191 | +class ConcreteCreatorA(Creator): |
| 192 | + def factory_method(self) -> Product: |
| 193 | + return ConcreteProductA() |
| 194 | +
|
| 195 | +class ConcreteCreatorB(Creator): |
| 196 | + def factory_method(self) -> Product: |
| 197 | + return ConcreteProductB() |
| 198 | +
|
| 199 | +if __name__ == "__main__": |
| 200 | + a = ConcreteCreatorA() |
| 201 | + b = ConcreteCreatorB() |
| 202 | + print(a.operation()) # Creator uses ConcreteProductA |
| 203 | + print(b.operation()) # Creator uses ConcreteProductB |
| 204 | +``` |
| 205 | + |
| 206 | +Python の場合、型チェックや依存関係注入を組み合わせてテストを容易にできます。 |
| 207 | + |
| 208 | +## 実務上の注意点(影響範囲の確認を必ず行う) |
| 209 | + |
| 210 | +- 影響範囲: `Creator` を拡張すると生成される `Product` の種類が増えるため、関連テスト・ドキュメント・ビルド影響を確認してください。特にシリアライズや API 境界で生成される型が変わると互換性影響が出ます。 |
| 211 | +- 曖昧さの回避: 「生成はどこで決まるか」を明確にし、責務をドキュメント化してください。生成ロジックが分散すると可読性が落ちます。 |
| 212 | +- テスト性: `Creator` をテスト用に差し替えられるように設計すると良い(テスト専用 `ConcreteCreator` の用意、または依存注入で `factory` を注入)。 |
| 213 | +- スタティックファクトリとの併用: 言語によっては静的ファクトリ関数やコンストラクタ注入で十分なケースもあります。パターン導入のコストと利得を比較してください。 |
| 214 | +- 不要な抽象化を避ける: シンプルな条件分岐で十分な場合は `Simple Factory` を選ぶのも現実的です。 |
| 215 | + |
| 216 | +## まとめ |
| 217 | + |
| 218 | +- `Factory Method` は生成責務をサブクラスに委譲し、クライアントを具象クラスから分離するパターンです。 |
| 219 | +- 小さな製品の切り替えや、生成の拡張が見込まれる場合に効果を発揮しますが、クラス数の増加や過剰設計には注意が必要です。 |
| 220 | +- 実装は言語特性に合わせて設計し、テスト・ドキュメント・影響範囲を必ず確認してください。 |
| 221 | + |
| 222 | +出典(一次情報抜粋): |
| 223 | +> "オブジェクト指向プログラミングにおいて、ファクトリメソッドパターンは、作成されるオブジェクトの正確なクラスを指定せずにオブジェクトを作成する問題に対処するためにファクトリメソッドを使用する生成パターンである。" — Wikipedia: Factory method pattern |
| 224 | +> https://en.wikipedia.org/wiki/Factory_method_pattern |
| 225 | + |
| 226 | +[!CARD](https://en.wikipedia.org/wiki/Factory_method_pattern) |
| 227 | + |
| 228 | +それでは、次回は `Abstract Factory` や `Builder` などの生成パターンの実践的な比較記事を予定しています。 |
| 229 | +この記事で提示したコードは学習目的に簡潔化しています。実運用に採用する際は要件に合わせて詳細設計・テストを行ってください。 |
| 230 | + |
| 231 | +以上、パン君でした! |
0 commit comments