SwiftでFactory Methodパターンを使ってみる

# Factory Methodについて
インスタンスの生成方法をスーパークラス(Swiftではプロトコルの場合も)で定め、具体的な処理をサブクラスで行うパターンをFactory Methodパターンと呼ぶ。
オブジェクトの生成と具体的な処理を分離することで、大幅に可読性が上がり、テストの柔軟性も向上する。


本記事では、上記のメリットを、Swiftのコードを用いて体感してみる。
Clean ArchitectureにFactory Methodパターンを適用してみる。今回はDomain層からPresentation層にデータを流す部分に焦点を当てる。

## Domain層
### Entity
```Message.swift
struct Message: Identifiable {
    var id: String {
        description
    }
    var description: String
    var email: String
}
```
上記のようなMessageを取得し、画面に表示するコードを書いてみる。

### UseCase
```MessageUse.swift
protocol MessageUseCase {
    var messages: [Message] {get set}
}
```

```MessageUseCaseImpl.swift
class MessageUseCaseImpl: MessageUseCase  {
    var messages: [Message]

    init() {
        self.messages = [
            .init(
                description: "hoge",
                email: "hoge@gmail.com"
            ),
            .init(
                description: "fuga",
                email: "fuga@gmail.com"
            )
        ]
    }
}
```
本来は、Data層からMessageを取得するので、UseCaseで状態管理などの実装が必要であるが、今回は諸々省略。

## Presentation層
### Presenter
```MessagePresenter.swift
class MessagePresenter: ObservableObject {
    @Published var messages: [Message]

    init(messages: [Message] = []) {
        self.messages = messages
    }
}
```

```MessagePresenterImpl.swift
class MessagePresenterImpl: MessagePresenter {
    let useCase: MessageUseCase

    init(useCase: MessageUseCase) {
        self.useCase = useCase
        super.init(messages: useCase.messages)
    }
}
```
### View
```MessageView.swift
import SwiftUI

struct MessageView: View {
    @StateObject var presenter: MessagePresenter

    var body: some View {
        List(presenter.messages) { message in
            Text(message.description)
        }
    }
}
```

### Preview
```swift
private extension MessagePresenter {
    static var mock: MessagePresenter {
        .init(messages: [
            .init(description: "Factory", email: "Factory"),
            .init(description: "Factory", email: "Factory")
        ])
    }
}

#Preview("Presenter") {
    MessageView(presenter: MessagePresenter.mock)
}

```
この実装でも、一見正しくモックは差し込めているが、もしメッセージについての画面以外も多数実装する必要がある、あるいは可能性がある状況であったり、複雑なロジックで生成された動的なPresenterのモックがいくつか必要な場合、より良い実装ができる。


### Factory
```PresenterFactory.swift
protocol PresenterFactory {
    func getMessagePresenter() -> MessagePresenter
    // 以下にMessage以外のPresenterの生成も書ける
}
```
```PresenterFactoryImpl.swift
class PresenterFactoryImpl: PresenterFactory {
    func getMessagePresenter() -> MessagePresenter {
        MessagePresenterImpl(useCase: MessageUseCaseImpl())
    }
    // 以下にMessage以外のPresenterの生成も書ける
}

```
このように、MessagePresenterのオブジェクトを返すメソッドを定義する。こうすることでPresenterの生成ロジックを他のViewでも共有でき、コードの可読性が向上する。
また、様々なUseCaseをPresenterに注入できるため、テストの柔軟性も向上する。

```MessageView.swift
struct MessageFactoryPatternView: View {
    @StateObject var presenter: MessagePresenter

    // viewFactoryを受け取るイニシャライザを追加
    init(viewFactory: MessagePresenterFactory) {
        _presenter = StateObject(wrappedValue: viewFactory.getMessagePresenter())
    }

    var body: some View {
        List(presenter.messages) { message in
            Text(message.description)
        }
    }
}

// Preview用のPresenterFactoryに準拠したFactory
private final class MessageViewFactory: PresenterFactory {
    func getMessagePresenter() -> MessagePresenter {
        MessagePresenter(messages: [
            .init(description: "Factory", email: "Factory"),
            .init(description: "Factory", email: "Factory")
        ])
    }
}

#Preview("Factory") {
    MessageFactoryPatternView(viewFactory: MessageViewFactory())
}
```
そして、Viewを上記のように書き換える。これで、Message以外のViewが存在する場合、オブジェクトの生成方法をすべてのPresenterで統一することができるようになった。

# まとめ
Factory Methodパターンはこのようなケース以外でも、様々な場面で応用できる。そしてオブジェクトの生成を分離するだけで、格段にスケーラビリティが向上することが分かった。大規模なアプリケーション開発では、このような設計も選択肢に入れると良いと思う。

# 参考
- [デザインパターン「Factory Method」](https://qiita.com/shoheiyokoyama/items/d752834a6a2e208b90ca)
- [Swiftで学ぶFactory Methodパターン【Swift Design Pattern】](https://qiita.com/shuntarouboy/items/3ad088f9dbea50983aad)