1. パターンの意図
抽象ファクトリ(Abstract Factory) は、関連するオブジェクト群を一貫性のある形で生成するためのインターフェースを提供する デザインパターンです。
解決する問題
- 製品群(例:Button、TextField、Dialog)をまとめて生成したい
- 生成する製品群を環境・テーマ・プラットフォームによって切り替えたい
- クライアントコードを変更せずに「全体の見た目や挙動」を切り替えたい
ポイント
- 複数の関連オブジェクトをまとめて生成
- クライアントは「どの工場を使うか」だけ選べば良い
- UI テーマやプラットフォームごとの製品群切替に有効
2. UML 図
3. Flutter / Dart 実装例
3.1 抽象製品
abstract class Button {
void render();
}
abstract class TextField {
void render();
}
3.2 具体製品
class MaterialButton implements Button {
@override
void render() => print("Material Button");
}
class CupertinoButton implements Button {
@override
void render() => print("Cupertino Button");
}
class MaterialTextField implements TextField {
@override
void render() => print("Material TextField");
}
class CupertinoTextField implements TextField {
@override
void render() => print("Cupertino TextField");
}
3.3 抽象ファクトリ
abstract class WidgetFactory {
Button createButton();
TextField createTextField();
}
class MaterialWidgetFactory implements WidgetFactory {
@override
Button createButton() => MaterialButton();
@override
TextField createTextField() => MaterialTextField();
}
class CupertinoWidgetFactory implements WidgetFactory {
@override
Button createButton() => CupertinoButton();
@override
TextField createTextField() => CupertinoTextField();
}
3.4 利用例
void main() {
WidgetFactory factory = MaterialWidgetFactory();
var button = factory.createButton();
var textField = factory.createTextField();
button.render(); // Material Button
textField.render(); // Material TextField
factory = CupertinoWidgetFactory();
factory.createButton().render(); // Cupertino Button
factory.createTextField().render(); // Cupertino TextField
}
4. Android / Kotlin 実装例
4.1 抽象製品
interface Button {
fun render()
}
interface TextField {
fun render()
}
4.2 具体製品
class MaterialButton : Button {
override fun render() = println("Material Button")
}
class CupertinoButton : Button {
override fun render() = println("Cupertino Button")
}
class MaterialTextField : TextField {
override fun render() = println("Material TextField")
}
class CupertinoTextField : TextField {
override fun render() = println("Cupertino TextField")
}
4.3 抽象ファクトリ
interface WidgetFactory {
fun createButton(): Button
fun createTextField(): TextField
}
class MaterialWidgetFactory : WidgetFactory {
override fun createButton(): Button = MaterialButton()
override fun createTextField(): TextField = MaterialTextField()
}
class CupertinoWidgetFactory : WidgetFactory {
override fun createButton(): Button = CupertinoButton()
override fun createTextField(): TextField = CupertinoTextField()
}
4.4 利用例
fun main() {
var factory: WidgetFactory = MaterialWidgetFactory()
factory.createButton().render()
factory.createTextField().render()
factory = CupertinoWidgetFactory()
factory.createButton().render()
factory.createTextField().render()
}
5. メリット / デメリット
メリット
- 関連製品群を一貫して生成できる
- クライアントコードを変更せずにテーマ・プラットフォームを切替可能
- UI やプラットフォームごとの互換性を保てる
デメリット
- クラス数が増える(抽象+具体ファクトリ+製品群)
- 単純なケースでは冗長になる
6. 実務ユースケース
Flutter
-
Material
とCupertino
の UI 切替 - マルチプラットフォーム向け Widget セットの切替
- 多言語・多ブランド UI の統一生成
Android (Kotlin)
- ダークテーマ / ライトテーマ用コンポーネント生成
- テスト環境用と本番環境用の Repository 切替
- UI コンポーネントのスキン切替
7. 実装上の注意点
Flutter / Dart
-
Factory Method との違いを明確に:
- Factory Method → 単一製品を生成
- Abstract Factory → 複数の関連製品群をまとめて生成
-
Theme.of(context)
に似た概念として理解するとわかりやすい
Android / Kotlin
-
DI (Hilt/Koin)
と併用するとテストしやすい - Factory を差し替えることで テスト用 UI コンポーネント を簡単に注入可能
8. どんなときに使う?
- 複数の製品群をまとめて生成したいとき
- プラットフォーム・テーマごとに関連するUIを切り替えたいとき
- 整合性のある一連のオブジェクトを提供したいとき
まとめ
- 抽象ファクトリは 「関連する製品群をまとめて生成する工場」
- Flutter / Android では UIテーマやプラットフォーム切替 に特に有効
- 単一生成が目的なら Factory Method、製品群なら Abstract Factory が適切
- 実務では DI と組み合わせることで保守性・拡張性を高められる