Factory — オブジェクトの生成をファクトリメソッドに委譲する生成パターンです。モバイル開発では、Factory MethodとAbstract Factoryを使用してViewModel、NetworkClient、Repositoryおよびその他の依存関係を作成します。 Factoryはインスタンス化のロジックを分離し、実装の置き換えを簡素化します。詳細は — Refactoring Guru: Factory Methodをご覧ください。
主要ポイント
Factory — GoFカタログの生成デザインパターンです。主なアイデア: オブジェクト生成ロジックをクライアントコードから別のメソッドまたはクラスに移動すること。クライアントはインターフェースまたは抽象クラスで動作し、具体的な実装はファクトリによって作成されます。これは依存性逆転の原則を実装します: クライアントは具象クラスに依存せず、抽象化のみに依存します。
2つの種類のFactory: Factory MethodとAbstract Factory。Factory Method — サブクラスがオーバーライドしてオブジェクトを生成するクラス内の単一メソッド。Abstract Factory — 関連オブジェクトのグループを生成するファクトリメソッドのファミリーを持つインターフェース。どちらのバリアントも同じ問題を解決します: クライアントは直接new MyClass()を呼び出さず、ファクトリにタイプまたはパラメータに従ってオブジェクトを生成するよう依頼します。
Factory vs new() — 直接のオブジェクト生成はコードを具象実装に強く結合させます。Factoryはレイヤーを追加します: 実装の変更にはファクトリのみの編集が必要で、全てのクライアントは不要です。モバイル開発では、FactoryはViewModel(ViewModelProvider.Factory)、ネットワーククライアント(Retrofit.create())、リストアダプター、シリアライゼーションファクトリの作成に積極的に使用されています。DIコンテナ(Dagger、Koin)は自動的にファクトリを生成します。
Factory Method — プロトコルまたは抽象クラスで宣言され、特定のタイプのオブジェクトを返すメソッドです。サブクラスがメソッドを実装して具体的なインスタンスを作成します。Swiftでは、プロトコルの静的メソッドまたは基底クラスのメソッドになります。Kotlinでは — ファクトリメソッドを持つcompanion objectまたは抽象クラスのopen funです。このパターンはパーサー、エラーファクトリ、クエリビルダーの作成に広く使用されています。
protocol PaymentGateway {
func processPayment(amount: Decimal) async throws -> PaymentResult
}
final class StripeGateway: PaymentGateway { /* ... */ }
final class ApplePayGateway: PaymentGateway { /* ... */ }
enum PaymentType { case stripe, applePay }
final class PaymentFactory {
// Factory Method
static func create(type: PaymentType) -> PaymentGateway {
switch type {
case .stripe: return StripeGateway()
case .applePay: return ApplePayGateway()
}
}
}
// 使用法
let gateway = PaymentFactory.create(type: .stripe)
Kotlin版のFactory Methodは、タイプを制限するためにcompanion objectまたはsealed classを使用します。Sealed classはwhenブランチが全ての可能なタイプをカバーすることを保証します — コンパイラが完全性をチェックします。これはファクトリがビルドフレーバーや設定に応じて異なるRepositoryまたはDataSourceの実装を作成するAndroidプロジェクトで一般的です。
sealed class PaymentType {
object Stripe : PaymentType()
object ApplePay : PaymentType()
}
interface PaymentGateway {
suspend fun processPayment(amount: BigDecimal): PaymentResult
}
class PaymentFactory {
companion object {
fun create(type: PaymentType): PaymentGateway = when (type) {
PaymentType.Stripe -> StripeGateway()
PaymentType.ApplePay -> ApplePayGateway()
}
}
}
Abstract Factory — 具象クラスを指定せずに関連または相互依存するオブジェクトのファミリーを生成するパターンです。クライアントは抽象ファクトリインターフェースで動作し、ファミリーの各製品を生成するメソッドを定義します。具象ファクトリがインターフェースを実装し、特定のバリアントのオブジェクトを作成します。例えば、iOS用のUIコンポーネントファクトリはUIButton、UILabel、UITableViewを作成し、Android用はButton、TextView、RecyclerViewを作成します。
Abstract Factory vs Factory Method — Factory Methodは継承を通じて1つのタイプのオブジェクトを作成し、Abstract Factoryはコンポジションを通じてオブジェクトのファミリーを作成します。Factory Methodはサブクラスでオーバーライドされ、Abstract Factoryはプロトコルを通じて複数のファクトリメソッドを提供します。Abstract Factoryはしばしば複数のFactory Methodを含みます。モバイル開発では、Abstract Factoryはプラットフォーム依存コンポーネント、テーマデザイン、データベースファクトリに使用されます。
| 特性 | Factory Method | Abstract Factory |
|---|---|---|
| 製品数 | 1つ | ファミリー(複数) |
| メカニズム | 継承(オーバーライド) | コンポジション(プロトコル/インターフェース) |
| iOSの例 | PaymentFactory.create() | iOS/Android用UIComponentFactory |
| Androidの例 | ViewModelProvider.Factory | ThemeFactory: ボタン、テキスト、カードの作成 |
| 柔軟性 | シンプルなサブクラス置換 | 完全なファミリー置換 |
実例 AndroidでのAbstract Factory — 単一のDatabaseFactoryインターフェースを通じた異なるデータベースタイプ(SQLite vs Room)の実装。ファクトリはDAOオブジェクト、マイグレーション、コネクションプールを作成します。iOSでは — 異なる環境(Development/Staging/Production)向けのサービスファクトリ。Abstract Factoryが直接使用されることは稀です — その機能はDIコンテナ(Dagger Module、Swinject Assembly)が担います。
Swift Factoryはプロトコルと静的メソッドを通じて実装されます。Factoryプロトコルは抽象タイプを返すcreate()メソッドを宣言します。具象ファクトリがプロトコルを実装し、必要なオブジェクトを作成します。Swiftは単純なケースでは別のファクトリクラスを必要としません — enumまたはstructの静的メソッドで十分です。複雑なシナリオでは、DIインジェクション付きのFactoryプロトコルが使用されます。
iOS SDKのFactory — 多くのシステムファクトリ: UIStoryboard.instantiateViewController(withIdentifier:)、NSKeyedUnarchiver.unarchivedObject(ofClass:from:)、JSONDecoder().decode(_:from:)。開発者はViewController(StoryboardFactory)、サービス(ServiceFactory)、データモデル用のファクトリを作成します。Factory MethodはVIPERおよびClean Swiftアーキテクチャで画面モジュールを作成するために積極的に使用されています。
Factory + DI — 最新の代替手段: DIコンテナ(Swinject、Factory)は登録されたタイプのファクトリを自動生成します。コンテナはオブジェクト作成のレシピを保存し、依存関係を解決します。Factoryライブラリ(github.com/hmlongco/Factory)は自動インジェクションに@Injected(.service)を使用します。DIファクトリは1行でモジュール全体を置き換えてテストされます: container.register { MockService() }。
Android Factory — 典型的な例: パラメータ付きViewModelを作成するViewModelProvider.Factory。Googleは自動ViewModelファクトリ生成にHiltの使用を推奨しています — @HiltViewModelアノテーションが自動的にFactoryを作成します。単純なオブジェクトには、create()またはinvoke()メソッドを持つcompanion objectが使用されます。Kotlinでは、invoke演算子によりファクトリを関数のように呼び出せます: Factory(param)。
Jetpack ComposeのFactory — ファクトリは状態と効果の作成に使用されます。remember { Factory.create() }は最初のレンダリング時にオブジェクトを作成し、composableのライフサイクル全体で保持します。ComposeのViewModelはviewModel()を介して作成されます — これはHiltによって管理されるファクトリです。Composeでは、DIとCompose StateManagerがオブジェクト作成を処理するため、ファクトリは明示的に使われることは稀です。
Factory vs Hilt — Dagger/Hiltはコンパイル時に自動的にファクトリを生成します。@Module + @ProvidesはFactory Methodを置き換え、@BindsはAbstract Factoryを置き換えます。手動ファクトリは実行時の動的実装選択(A/Bテスト、フィーチャーフラグ)に関連性を保ちます。静的依存関係については、Hiltがオブジェクト作成を完全に自動化します — 開発者はインターフェースとアノテーションのみを記述します。
よくある質問
Factory Methodは継承を通じて1つのタイプのオブジェクトを作成します — サブクラスがファクトリメソッドをオーバーライドします。Abstract Factoryはコンポジションを通じてオブジェクトのファミリーを作成します — ファクトリインターフェースが複数の製品のメソッドを宣言します。Factory Methodはよりシンプルで、Abstract Factoryはプラットフォーム依存またはテーマ別コンポーネントに対してより柔軟です。
Factoryは実行時の動的実装選択(A/Bテスト、フィーチャーフラグ、異なるティア向けの異なるAPI)に適しています。DI(Hilt、Dagger、Koin)は静的依存関係に推奨されます — 作成と注入を自動化します。FactoryとDIは相互排他的ではありません: DIはモジュール内でFactoryを使用できます。
Factoryはプロトコルを通じてファクトリを置き換えることでテストされます。テストでは、同じプロトコルを実装しモックオブジェクトを返すTestFactoryが作成されます。静的Factoryメソッドの場合、テストはより複雑です — DIコンテナまたはswizzlingが必要です。テスト容易性を維持するために、Factoryには常にプロトコルを使用することをお勧めします。
ViewModelProvider.FactoryはJetpackのインターフェースで、カスタムパラメータを持つViewModelを作成できます。ファクトリがない場合、ViewModelはリフレクションを通じて作成され、空のコンストラクタのみを持つことができます。Factoryはパラメータ(リポジトリ、アプリケーションコンテキスト)を受け取り、ViewModelコンストラクタに渡します。Hiltは@HiltViewModelに対して自動的にFactoryを生成します。
Factoryは開放/閉鎖の原則を実装します: システムは拡張に対して開いています(新しい実装がファクトリに追加されます)が、修正に対して閉じています(クライアントコードは変更されません)。新しい製品タイプの追加にはファクトリのみの編集が必要で、全てのクライアントは不要です。これが直接オブジェクト生成に対するFactoryの主な利点です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。