UI アーキテクチャパターン - MVI#
MVC/MVVM/MV の問題#
MVC/MVVM/MV はすべて View と Model を分離していますが、Model/ViewModel/StatefulModel では View の状態を処理および保存する必要があるため、ページの相互作用やコンポーネントの開発が複雑になると、アプリケーション全体の状態の一貫性を保つことが困難になります。
MVI とは#
MVI パターンは Model-View-Intent パターンの略です。MVI は処理ロジックを Model、View、Intent の 3 つの部分に分割します。Model はデータとビジネスロジックを処理し、View は UI のレンダリングとユーザーの相互作用を担当し、Intent はユーザーの入力アクション、View のイベント、Model の状態変化などを Intent にカプセル化し、Intent を Model に送信し、Model が処理した後に View に送信してレンダリングします。この方法により、アプリケーション全体の状態の一貫性が保たれ、複雑な UI 状態の同期問題を比較的簡単に処理することができます。
View(Model(Intent()))
MVI と MVC/MVVM/MV の違い#
MVC/MVVM/MV と比較して、MVI はデータフローと状態管理により重点を置き、単方向のデータフローと単一の信頼できるソースの原則を強調しています。MVC/MVVM/MV は、MVI のデータフローと状態管理の考え方を採用して改善することができ、アプリケーションのメンテナンス性と拡張性を向上させることができます。したがって、MVI は MVC/MVVM/MV と完全に独立しているのではなく、それらに基づいた深い実践と拡張の一種です。
MVI の使用#
MVI は統一された状態を使用して UI の状態の一貫性の問題を解決し、Intent-Reducer-State の単方向のデータフローを使用して複雑な状態間の関係を解決します。
selector : (state)->state
render : (state)
[View]
package ViewModel {
[UiState]
[UiIntent]
[Reducer]
}
[UiState] -up-> [View] : observe(selector,render)
[View] -down-> [UiIntent] : dispatch(intent)
[UiIntent] -down-> [Reducer]
[Reducer] -up-> [UiState] : reduce(intent,state) -> state
MVI とコンポジションパターン#
MVI アーキテクチャでは、各画面コンポーネントは独自の State と Intent を持ち、これらの State と Intent は組み合わせて画面全体の State と Intent を構成します。この方法により、画面の状態とユーザーの動作をより良く管理し、コードの組織がより明確になり、保守性が向上し、大規模なアプリケーションの開発でも効率が向上します。
class Page
class View1
class View2
class View1State
class View2State
class PageState
Page *-left- View1
Page *-right- View2
PageState *-left- View1State
PageState *-right- View2State
View1 -down-> View1State
View2 -down-> View2State
data class View1Intent
data class View2Intent
data class PageIntent{
View1(val state:View1State):PageIntent
View2(val state:View2State):PageIntent
}
fun dispatch(intent:PageIntent){
when(intent){
is View1 -> dispatch(View1.sate)
is View2 -> dispatch(View2.sate)
}
}