Usecase
UseCase(ユースケース)の位置づけは「画面(UI)の都合で分ける」のではなく、「アプリケーションが提供するビジネスロジック(機能)やドメインロジックを表す」ための単位として定義されるものです。
画面ごとにまったく同じロジックを複製して作るのではなく、「何をするためのロジックか?」という観点で UseCase を定義し、そのロジックが必要になる画面や処理フローから再利用される、という考え方になります。
1. UseCase とは「アプリケーションが外部に提供する操作(機能)」を表す
たとえば、「ユーザ情報を取得する」「商品一覧を検索する」「ログインする」など、アプリとして実現したい操作があるとします。
- これらはユーザが行う行為やアプリが提供するサービスを表すため、
- 画面(HomeやSettingなど)がどこであろうと、共通の処理が必要な場面では同じユースケースを使います。
「画面依存」ではなく「機能依存」で設計する
- 「Home 用のユースケース」「UserInfo 用のユースケース」と分けるよりは、「UserInfo を取得するユースケース」 という形で、機能ごとにひとつのクラスやメソッドを作るイメージです。
- それを必要としているのが Home 画面か Profile 画面かは関係なく、共通で再利用できます。
2. 同じロジックを複数箇所で使うときの利点
● ロジックの重複を防ぐ
もし Home 用と UserInfo 用でそれぞれ同様の処理(たとえば「ユーザ情報を取得する」)を実装したら、コードが重複し、修正やバグ対応が複数箇所で必要になります。
共通するビジネスロジックは1か所にまとめ、そこを呼び出すことがメンテナンス性を高めます。
● テストがしやすい
ユースケース単位でテストコードが書けるため、UI の画面ごとに差分があっても、ビジネスロジックのテストは一度書けばカバーできる利点があります。
3. アプリケーション層(UseCase)とプレゼンテーション層の関係
- プレゼンテーション層(Notifier や View) は「ユーザに何を表示・入力させるか」の責務。
- UseCase は「アプリとして何をするのか」を司る責務。
- 画面(HomeView など)から「ユーザ情報が必要になった」ときに、HomeNotifier が
fetchUserInfo()のように「ユーザ情報を取得するユースケース」を呼び出せばいいわけです。 - 同じ
fetchUserInfo()は、もし他の画面で必要なら、同じものを呼び出して使えば良いのです。
4. 具体例
ユースケース例
class FetchUserInfoUseCase {
final UserRepository userRepository;
FetchUserInfoUseCase(this.userRepository);
Future<UserInfo> call() async {
// DB or API からユーザ情報取得
final userInfo = await userRepository.getUserInfo();
// 取得したデータを整形したりバリデーションをしたりするビジネスロジックをここに書く
return userInfo;
}
}
Notifier からの呼び出し
class HomeNotifier extends StateNotifier<HomeState> {
HomeNotifier(this._fetchUserInfoUseCase) : super(HomeState.initial());
final FetchUserInfoUseCase _fetchUserInfoUseCase;
Future<void> loadUserInfo() async {
try {
state = state.copyWith(isLoading: true);
final info = await _fetchUserInfoUseCase();
state = state.copyWith(isLoading: false, userInfo: info);
} catch (e) {
// エラー処理
state = state.copyWith(isLoading: false, error: e.toString());
}
}
}
Home 画面も Profile 画面もユーザ情報が必要であれば、それぞれの Notifier から同じユースケースを注入し、呼び出すだけです。
「Home 専用の fetchUserInfo()」と「Profile 専用の fetchUserInfo()」を別々に実装する必要はありません。
5. まとめ
- UseCase とは、「ユーザや外部から見たアプリの操作単位」 でビジネスロジックをまとめるものです。画面単位ではなく、機能や動作単位で定義するイメージ。
- どの画面から呼ぶかは意識しすぎず、「何をしたいのか?」 にフォーカスして、重複しうるロジックを1か所に集約するのがポイントです。
- 結果として、複数の画面で同じ処理が必要な場合、同じ UseCase を使い回せるので、保守性・再利用性・テストしやすさが向上します。
以上のように、UserInfo 用の UseCase は“ユーザ情報の取得・更新”に関するロジックを集約したクラスと考えるとわかりやすいです。Home であろうが別画面であろうが、そのロジックが必要なタイミングで同じ UseCase を呼び出せば OK です。
Robert C. Martin(クリーンアーキテクチャの提唱者)のブログ:
ResoCoder(Flutter開発の教育サイト)のクリーンアーキテクチャガイド:
UserInfo 用の UseCase は“ユーザ情報の取得・更新”に関するロジックを集約したクラスと考えるとわかりやすい。Home であろうが別画面であろうが、そのロジックが必要なタイミングで同じ UseCase を呼び出せば OK ってこと?