Rəsmi arxitektura: state hansı layer-də yaşayır
Flutter komandasının rəsmi arxitektura bələdçisi iki əsas layer verir:
UI layer
- View — widget kompozisiyası. Bələdçiyə görə view-da yalnız minimal məntiq olmalıdır: flag-a görə widget göstərmək/gizlətmək, animasiya məntiqi, cihaz məlumatına görə layout, sadə routing. Məlumatla bağlı bütün məntiq view model-də olmalıdır.
- View model — repository-dən gələn məlumatı UI state-inə çevirir və view-un rebuild olarkən məlumatı itirməməsi üçün cari state-i saxlayır. View-a command adlanan callback-lər açır.
Data layer
- Repository — model məlumatı üçün həqiqətin mənbəyi (source of truth): cache, xəta idarəsi, təkrar cəhd, xam məlumatın domain modelinə çevrilməsi.
- Service — xarici API-ları (REST, platforma, fayl) örtür və state saxlamır.
Opsional domain layer — use-case/interactor: bir neçə repository-dən məlumat lazım olduqda, məntiq çox mürəkkəb olduqda, ya da bir neçə view model tərəfindən təkrar istifadə edildikdə.
| Sual | Bələdçinin cavabı |
|---|---|
| View ilə view model arasındaki əlaqə | Bir-bir (one-to-one) |
| View model ilə repository | Çoxdan-çoxa; bir repository bir neçə view model tərəfindən istifadə oluna bilər |
| Repository-lər bir-birini tanıyırmı? | Xeyr. İki repository-nin məlumatı lazımdırsa, birləşdirmə view model-də və ya domain layer-də aparılır |
| Tətbiq boyu paylaşılan sessiya state-i | Repository-də — o, məlumat üçün vahid həqiqət mənbəyidir və app-wide lifecycle state üçün ideal yerdir |
| Ekrana bağlı UI state-i | View model-də — view rebuild olarkən itməməsi üçün |
Bələdçi bu strukturu MVVM ilə eyniləşdirir: "Model-View-ViewModel arxitektur pattern-i ilə tanışsınızsa, bu sizə tanış gələcək." Vacib nüans: bələdçi konkret state management library-si tövsiyə etmir — prinsiplər Provider, Riverpod və BLoC ilə eyni dərəcədə tətbiq olunur. Müsahibədə bu, güclü mövqedir: "arxitektura library seçimindən əvvəl gəlir".
// Data layer: service state saxlamır.
class BookingApiClient {
Future<List<BookingDto>> fetch() async { /* ... */ }
}
// Data layer: repository — həqiqətin mənbəyi, domain modelinə çevirir.
class BookingRepository {
BookingRepository({required BookingApiClient apiClient})
: _apiClient = apiClient;
final BookingApiClient _apiClient; // asılılıq private saxlanılır
Future<List<Booking>> loadAll() async {
final dtos = await _apiClient.fetch();
return dtos.map(Booking.fromDto).toList();
}
}
// UI layer, variant A — Provider: ChangeNotifier view model.
class BookingViewModel extends ChangeNotifier {
BookingViewModel({required BookingRepository repository})
: _repository = repository;
final BookingRepository _repository;
// ...
}
// UI layer, variant B — Riverpod: AsyncNotifier view model.
class BookingNotifier extends AsyncNotifier<List<Booking>> {
@override
Future<List<Booking>> build() =>
ref.watch(bookingRepositoryProvider).loadAll();
}
// UI layer, variant C — BLoC: view model rolunda bloc.
class BookingBloc extends Bloc<BookingEvent, BookingState> {
BookingBloc(this._repository) : super(const BookingState()) {
on<BookingStarted>((event, emit) async { /* ... */ });
}
final BookingRepository _repository;
}Eyni arxitektura, üç library — dəyişən yalnız notifier-in tipidir.
📚 Mənbələr və sənədlər
- Flutter arxitektura bələdçisirəsmidocs.flutter.dev
Bu mövzudaki bütün qaydaların mənbəyi: layer-lər, əlaqələr, view-da nə qədər məntiq.
- Arxitektura konseptlərirəsmidocs.flutter.dev
- Case study: Compass tətbiqirəsmidocs.flutter.dev
Prinsiplərin real kod bazasında necə göründüyü.
- Command pattern-irəsmidocs.flutter.dev
View model-in view-a açdığı callback-lərin rəsmi formalaşdırılması.