Sparround

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ə.

SualBə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-iRepository-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-iView 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".

dart
// 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