アプリ開発においてよく耳にする”MVVM”について、
その基本を分かりやすくまとめました。
Flutterで実装した場合のコード例もご紹介します。
MVVMの概要
MVVM(Model-View-ViewModel)とは、
アプリのロジックとUI(ユーザーインターフェース)を分けて、
開発の効率化と保守性の向上を目指したソフトウェア設計手法です。
“画面表示”、”データ操作”、”データ定義”等の役割ごとに設計する手法の1つです。
似たような考え方でMVCなど手法が存在します。
MVVMの構成要素
MVVMの構成は、Model、View、ViewModelの3つです。
View
ユーザーに表示されるUI部分
表示するデータはViewModelから取得する
Flutterでは、Widgetで表現される
ViewModel
アプリの複雑なロジックを担う部分
Viewに渡すデータを加工(計算や判定など)
データはModelから取得する
Model
データの定義や、データに対するCRUD操作を行う
Repository(補足)
初期データの取得や永続データの保存時に使用します。
DBのCRUD処理やデータ加工を行い、ViewModelへデータを渡す。
MVVMの各要素の関係
構造要素のそれぞれの関係は以下の通りです。
Flutterでは、Riverpod等を利用して状態の変化を検知します実装されます。
Riverpodを使用することで、ViewModelやModelの状態の変化がViewで検知され、
画面が再描画される流れを作り出します。
MVVMの利点
MVVMの最大の利点は、表示(View)、動作(ViewModel)、データ(Model)が
分離されているため、それぞれがシンプルになり、管理しやすくなる点です。
しかし、欠点としてModelに変更があった場合、ViewModelやViewにも
影響を与える可能性があり、逆に変更範囲が増える恐れもあります。
MVVM及びRepositoryのコード例とその説明
以下はFlutterでのMVVMパターンをRiverpodを用いて実装した例です。
// Userモデル
class User {
final String name;
final String email;
User(this.name, this.email);
}
// Repository
// 実際にはDBやAPIからデータを取得しますが、今回は固定値のデータを返しています
class UserRepository {
Future<User> fetchUser() async {
return User('Goda Takeshi', 'Jaian@com');
}
}
// UserViewModel
final userProvider = FutureProvider<User>((ref) async {
final repository = UserRepository();
return repository.fetchUser();
});
// UserView
class UserView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userProvider);
return Scaffold(
appBar: AppBar(title: Text('MVVM Example')),
body: user.when(
data: (user) => Text('User Name: ${user.name}'),
loading: () => CircularProgressIndicator(),
error: (e, stack) => Text('Error: $e'),
),
);
}
}
UserViewが「final user = ref.watch(userProvider)」でuserProviderを監視しています。
userProviderでは、Userクラスで型定義して、UserRepositoryを呼び出しています。
UserRepositoryでは、固定値を返していますが、
実際のアプリではDBやAPIからデータを取得したり、更新したりする処理が実装されます。
最後に
MVVMの設計について、ご紹介しました。
Flutterの設計には、MVVMが絶対に良いという話ではなく、アプリやプロジェクトによって、
設計手法は使い分けることが良いと思います。
本記事により、少しでもMVVMについて理解ができ、
この設計手法を取り入れたアプリについて、読みやすくなれば幸いです。