DEV Community

Cover image for Flutter Architecture ­čĺź ­čîî ÔťĘ
G├╝lsen Keskin
G├╝lsen Keskin

Posted on

 

Flutter Architecture ­čĺź ­čîî ÔťĘ

Image description

app flutter.onError kilitlenme i┼čleme ve ba─č─▒ml─▒l─▒k ba┼člatma gibi ├že┼čitli kurulumlara sahip run_app uygulamas─▒n─▒ i├žerir.

common t├╝m katmanlar i├žin ortak olan ve t├╝m katmanlar taraf─▒ndan eri┼čilebilen kodu i├žerir.

device cihaz donan─▒m─▒ (├Ârn. sens├Ârler) veya yaz─▒l─▒m (takvim, izinler) ile ileti┼čimi temsil eden bir d─▒┼č katmand─▒r.

source_remote uzak kaynaklarla (web, http istemcileri, soketler) ileti┼čimi temsil eden bir d─▒┼č katmand─▒r.

source_local yerel kaynaklarla (veritaban─▒, shared_prefs) ileti┼čimi temsil eden bir d─▒┼č katmand─▒r.

domain genellikle interactor ve data holderlar─▒ i├žeren i├ž katmand─▒r. Bu katman yaln─▒zca i┼č mant─▒─č─▒n─▒ i├žermeli ve ui, web vb. veya di─čer katmanlara ├Âzg├╝ bilgileri bilmemelidir.

ui widget'lar─▒ ve providerlar taraf─▒ndan paketledi─čimiz katmand─▒r. Provider'lar sunum mant─▒─č─▒ i├žerir ve etki alan─▒na eri┼čirler.

├ľnceden tan─▒mlanm─▒┼č katmanlarda s─▒kl─▒kla kullanaca─č─▒m─▒z birka├ž s─▒n─▒f vard─▒r.

Image description

Repository ve Manager

Repository, uygulamam─▒z─▒n d─▒┼č k─▒sm─▒d─▒r. source_remote, source_local veya device'a aittir. Dio, Hive, add2calendar, di─čer eklentiler gibi somut uygulamalar─▒ kullan─▒r ve bunlar─▒ uygulaman─▒n geri kalan─▒ndan soyutlar.

Repository bir aray├╝z├╝n (interface) arkas─▒nda olmal─▒d─▒r. Bu, YourRepository interface'ini olu┼čturman─▒z ve YourRepositoryImpl'i YourRepository'e implemente etmektir.
YourRepository interface'i domain'e, YourRepositoryImpl ise d─▒┼č katmanlara aittir.
Bu ┼čekilde domain repository'e eri┼čebilir.


//domain/repository/meetup_repository/meetup_repository.dart

abstract class MeetupRepository {
  Future<List<Meetup>> getListOfMeetups();
}


//source_remote/impl/meetup_repository/meetup_repository_impl.dart

class MeetupRepositoryImpl implements MeetupRepository {
  MeetupRepositoryImpl(this._dio);

  final Dio _dio;

  @override
  Future<List<Meetup>> getListOfMeetups() async {
    final Response<String> response = await _dio.post<String>('/api/meetups');
    return MeetupsResponse.fromJson(jsonDecode(response.data)).meetups;
  }
}

Enter fullscreen mode Exit fullscreen mode

Manager, Repository ile ayn─▒ ┼čekilde ├žal─▒┼č─▒r, Manager'─▒ yaln─▒zca daha iyi adland─▒rma i├žin kullan─▒r─▒z. Bazen bu katman, ├Ârne─čin takvime etkinlik ekleyerek, bluetooth'u a├žarak veya izinleri y├Âneterek etkin bir ┼čekilde y├Ânetebilir. Onlara BluetoothRepository demek yerine BluetoothManager gibi bir isim kullan─▒r─▒z.

Interactor (etkile┼čimci):

Interactor, domaine ait olan i├ž k─▒s─▒md─▒r.
Interactor, uygulaman─▒n i┼č mant─▒─č─▒n─▒ i├žerir, repository'ler dahil olmak ├╝zere domainden di─čer s─▒n─▒flara eri┼čebilirler.
Interactor ayr─▒ca daha kolay test i├žin bir interface'in arkas─▒ndad─▒r, bu nedenle YourInteractorve YourInteractorImpl'i olu┼čturuyoruz.
Interactor'─▒n ana i┼či, farkl─▒ repository'leri birle┼čtirmek ve i┼č mant─▒─č─▒n─▒ y├Ânetmektir.

Takvime bulu┼čma etkinli─či eklemek i├žin interactor ├Ârne─či:


//domain/interactor/add_event_to_interactor/add_event_to_interactor.dart

abstract class AddEventToCalendarInteractor {
  Future<void> addEventToCalendar(Meetup event);
}

//domain/interactor/add_event_to_interactor/add_event_to_interactor_impl.dart

class AddEventToCalendarInteractorImpl extends AddEventToCalendarInteractor {
  AddEventToCalendarInteractorImpl(this._calendarManager, this._meetupRepository);

  final CalendarManager _calendarManager;
  final MeetupRepository _meetupRepository;

  @override
  Future<void> addEventToCalendar(Meetup meetup) async {
    final dateTimeOfEvent = await _meetupRepository.getMeetupEventDate(meetup);

    final CalendarEvent event = CalendarEvent(meetup.name, dateTimeOfEvent);

    return await _calendarManager.addEventToCalendar(event);
  }
}
Enter fullscreen mode Exit fullscreen mode

Provider ve widgetlar

Provider ve widget'lar, kullan─▒c─▒ aray├╝z├╝ne koydu─čumuz sunumun bir par├žas─▒d─▒r.
Birlikte ├žal─▒┼čt─▒klar─▒ i├žin gezinmeyi kolayla┼čt─▒ran katmanlar halinde paketlenirler.
Provider, genellikle g├Âr├╝n├╝m durumunu kontrol eden sunum mant─▒─č─▒n─▒ (presentation logic) i├žerir.
Widget bu durumu g├Âzlemler ve state de─či┼čikli─čini yeniden olu┼čturabilir.(rebuild)

Bu ┼čekilde g├Âr├╝n├╝m pasiftir ve sadece de─či┼čikliklere tepki verir.
Bak─▒m─▒ ve testi kolayd─▒r.
G├Âr├╝n├╝m, ├žo─čunlukla, provider g├Âr├╝n├╝m durumunu g├Âzlemleyen stateless (durumsuz) widget'lardan olu┼čmal─▒d─▒r.

Provider ├Ârne─či:


//ui/meetup/provider/meetup_screen_provider.dart

class MeetupScreenProvider extends ChangeNotifier {
  MeetupScreenProvider(this._addEventToCalendarInteractor);

  final AddEventToCalendarInteractor _addEventToCalendarInteractor;
  final AddMeetupToFavoritesInteractor _addMeetupToFavoritesInteractor;

  void onAddToCalendar(Meetup meetup) {
    _addEventToCalendarInteractor.addEventToCalendar(meetup);
  }

  void onMeetupFavorite(Meetup meetup) {
    _addMeetupToFavoritesInteractor.addToFavorites(meetup);
  }

}
Enter fullscreen mode Exit fullscreen mode

Provider'a tepki veren ve yeniden olu┼čturan kullan─▒c─▒ aray├╝z├╝ ├Ârne─či:

    Consumer<MeetupScreenProvider>(
      builder: (context, provider, _) {
        return _MeetupList(list: provider.state);
      },
    ),
Enter fullscreen mode Exit fullscreen mode

─░stek, y├╝kleme, ba┼čar─▒ ve hata gibi de─čerlerle ba┼čl─▒ ba┼č─▒na bir state'dir.
Bu nedenle, genellikle istekleri hepsi bir arada providerda di─čer t├╝m state'ler ile birlikte tek bir mega durumda paketlemiyoruz.
Loading indicator veya hatalar─▒ g├Âstermek i├žin genellikle tam olarak bir request state'ini (istek durumunu) dinlemeniz gerekti─činden, provider mega state de dinleyen t├╝m dinleyicileri g├╝ncelleyece─činden sorunlara neden olur.
Bu mega sa─člay─▒c─▒ da b├╝y├╝k ve bak─▒m─▒ zor olabilir.

Modeller

Modeller basit veri yap─▒lar─▒d─▒r.
Genellikle common klas├Âr├╝n├╝n (/common /models) alt─▒nda bulunurlar.
Birden ├žok katman taraf─▒ndan kullan─▒lan modellerdir.
├ľrne─čin, source_remote taraf─▒ndan kullan─▒lan @JsonSerializable ├Âzelli─čine sahip kullan─▒c─▒n─▒z olabilir, ancak ayn─▒ model domain ve UI taraf─▒ndan da kullan─▒l─▒r.

Ayr─▒ca belirli bir katman─▒n (/source_remote/model veya ui/my_feature/model) veya belirli bir ├Âzelli─čin (/domain/manager/permission_manager/device_permissions.dart) par├žas─▒ olarak modelleriniz olabilir.

T├╝m bu modelleri ay─▒rt etmek i├žin baz─▒ katmanlar i├žin ├Âzel adland─▒rmalar vard─▒r.
UI modellerine Ui (├Âr. ArticleUi) ekliyoruz ve domain modeli ekranda g├Âsterilmesi gerekene uymad─▒─č─▒nda bunu kullan─▒yoruz.
Bu modeller sadece kullan─▒c─▒ ara y├╝z├╝nde kullan─▒l─▒r.

Di─čer d─▒┼č katmanlardan gelen modeller, Veri Aktar─▒m Nesnesi anlam─▒na gelen Dto ile eklenir (├Ârne─čin, ArticleDto).
Bunlar─▒, d─▒┼č katmanlardan ald─▒─č─▒m─▒z yap─▒ (API gibi) ├žal─▒┼čmak istedi─čimiz formatta olmad─▒─č─▒nda kullan─▒r─▒z, bu nedenle ArticleDto (API modeli) ve Article (uygulamam─▒z i├žin model) olu┼čtururuz.

─░├ž katman─▒n d─▒┼č katmanlar─▒n ├Âzelliklerini bilmemesi gerekti─čini s├Âyledi─čimiz gibi, burada da ayn─▒s─▒ ge├žerli.
Domain, Ui veya Dto modellerini asla bilmemelidir.
Repository veya provider da map'lenmeleri gerekir.

Data holders

DataHolder, verileri bellekte tutan tek bir s─▒n─▒ft─▒r (singleton class).
Bir interface'i yoktur ve yaln─▒zca veri almak veya veri ayarlamak i├žin veri ve y├Ântemlere sahiptir.
Data holder'lar domain'in bir par├žas─▒d─▒r ve repository veya di─čer d─▒┼č katmanlar─▒ ├ža─č─▒rmazlar.

Mappers

Bunlar, modelleri farkl─▒ katmanlar aras─▒nda e┼čleyecek statik y├Ântemlere sahip s─▒n─▒flard─▒r.

ArticleDto -> Article mapping i├žin ArticleMapper'─▒ olu┼čturuyoruz.
Tam tersi i├žin Article -> ArticleDto, ArticleDtoMapper'─▒ olu┼čturuyoruz.

Mapper (e┼čle┼čtirici) birden ├žok y├Ânteme sahip olabilir:

class ArticleMapper {
  Article map(ArticleDTO dto){...}
  Article mapFromXyz(XyzDTO dto){...}
  List<Article> mapToList(List<ArticleDTO> dto){...}
}
Enter fullscreen mode Exit fullscreen mode

Mapper'lar, ui, source_remote, device ve di─čer d─▒┼č katmanlar─▒n (/source_remote/mapper) par├žas─▒d─▒r. Stateless widget'─▒n─▒z kullan─▒c─▒ aray├╝z├╝ veya DTO'lar gerektirmiyorsa, mapper'lara ihtiyac─▒n─▒z yoktur.

resource

Top comments (0)

Super Useful CSS Resources

A collection of 70 hand-picked, web-based tools which are actually useful.
Each will generate pure CSS without the need for JS or any external libraries.