見出し画像

iOS 開発における MVVM の Model の実装について

概要

iOS 開発に置いて MVVM が流行りはじめてから随分時間が経ったと思います。

その間にたくさんの方が MVVM や RxSwift に関する知見を公開してくださっていて、自分も参考にさせていただいていました。

しかしその中でも MVVM における Model の実装について色々思うことがあったのでまとめてみます。

Model の実装について思うこと

いろんな記事や OSS の Model の実装を見てみると、結構バラバラなことがわかりました。パターンとしては以下のようになっていました。

1. Model で通信処理等を定義し、結果を Observable で流す

このパターンが一番多いと思います。
Model にあたるクラス等で通信を行い、結果を Observable として ViewModel に公開するパターンです。

Model は通信処理を実装した APIClient や、Repository パターンで作成された Repository に対して依存関係を持っていたりします。

class Model {

    func fetchSomeData() -> Observable<SomeData> {
        // APIClient のようなクラスで通信処理を実行
        return APIClient.call(with: SomeDataRequest())
    }
}

2. Model を API のレスポンスとして定義している

xxModel のようなクラス等はなく、代わりに API のレスポンスが定義されているパターンです。

じゃあ通信等はどうするのかと言うと、Service クラスのようなものに対して ViewModel は依存関係を持っていて、それを通して行っているものが多い印象です。( Service クラス等が Model の役割になっているのかもしれません )

class ViewModel {

    private let service: SomeService
    
    init(service: SomeService) {
        self.service = service
        
        // ここで subscribe したりストリームを合成、変換して View に結果を伝える.
    }
}

3. Model が通信処理等の結果を持つ

Model で通信等の処理を行い、結果を BehaviorRelay 等で保持し、ViewModel に公開するパターンです。

MVC の Model に似たような役割をするパターンです。

class Model {
    
    private let someDataRelay = BehaviorRelay<SomeData>
    
    // Observalbe として ViewModel に公開.
    var someDataStream: Observable<SomeData> {
        return someDataRelay.asObservable()
    }
    
    func fetch() {
        APIClient.call(with: SomeDataRequest())
            .subscribe(onNext: { [weak self] response in
                self?.someDataRelay.accept(response)
            })
            .disposed(by: disposeBag)
    }
}

他にも細かい部分が違う物もあるかもしれませんが、大体こんな感じのパターンになると思います。

MVVM 初心者の頃は「MVVM と一括りにしてもこれだけ Model の実装にパターンがあって、どれがいいの?」と思っていました。

そもそも MVVM の Model とは

手元にある iOSアプリ設計パターン入門 には以下のように記されていました。

Model は UI に関係しない純粋なドメインロジックやそのデータを持ちます。MVVM における Model は MVC、MVP における Model と同じ立ち位置です。
MVVM は GUI アーキテクチャに属するため、Model の詳細な責務分けについては関知しません。

なるほど、MVC と同じなら Model はデータを保持し、データの変更等があれば通知するような作りである 3 の Model が正しいのかな?

とはいえ

設計に正解はなく、自分にしっくりくる書き方で作るのが一番だと思います。

今まで 1 と 3 のパターンは実装したことがあるので、それぞれ個人的に感じたメリット、デメリットを挙げてみます。

■ 1 のパターン

Model は結果を流すだけなので、あまり考えずに早く実装することができます。その代わりに ViewModel で Subscribe したりする必要が出てくるので、コード量が多くなりがちです。Model、ViewModel のテストが書けますが、Model のテストはそこまで色んなことは確認できません。

■ 3 のパターン

Model にビジネスロジック、データの保持、通知の役割を持たせるため ViewModel がスリムになり、Model と View 間の橋渡しの役割に集中することができます。その代わりに Model ですべき処理をある程度考える必要が出てくるので、実装スピードは落ちます。

今は 3 のパターンで作るのが一番テストが書けて、ViewModel もスリムになって気に入っています。次は 3 のパターンで簡単なアプリを作って紹介したいと思います。

この記事が気に入ったらサポートをしてみませんか?