Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
January 27, 2022 09:42 pm GMT

Flutter Uygulama Mimarisi: Repository Pattern

Tasarm kalplar, yazlm tasarmnda sk karlalan sorunlar zmemize yardmc olan kullanl ablonlardr.

Uygulama mimarisi (app architecture) sz konusu olduunda, yapsal (structural) tasarm kalplar, uygulamann farkl blmlerinin nasl dzenlendiine karar vermemize yardmc olabilir.

Bu balamda, backend API gibi eitli kaynaklardan veri nesnelerine (data objects) erimek ve bunlar uygulamann domain katmanna (i mantmzn yaad yer olan) type-safe (tr gvenli) varlklar olarak kullanlabilir hale getirmek iin repository pattern' kullanabiliriz.

Ve bu makalede repository pattern' ayrntl olarak reneceiz.
Nedir ve ne zaman kullanlr?
Baz pratik rnekler
Abstract (soyut) ve concrete (somut) snflar

Repository Design Pattern' Nedir?

Bunu anlamak iin aadaki mimari diyagram ele alalm:

Image description

Bu balamda, veri katmannda (data layer) depolar (repositories) bulunur. Ve onlarn ii:

Domain modellerini (ya da entities) veri katmanndaki (data layer) veri kaynaklarnn uygulama ayrntlarndan ayrn.

Veri aktarm nesnelerini (data transfer objects), domain katman tarafndan anlalan dorulanm varlklara (entities) dntrn.

(istee bal olarak) data caching (veri nbellee alma) gibi ilemleri gerekletirin.

Yukardaki ema, uygulamanzn mimarisini oluturmann birok olas yolundan yalnzca birini gstermektedir. MVC, MVVM veya Clean Architecture gibi farkl bir mimariyi takip ederseniz iler farkl grnecektir, ancak ayn kavramlar geerlidir.

Ayrca widget'larn , i mant (business logic) veya a koduyla hibir ilgisi olmayan sunum katmanna (presentation layer) nasl ait olduuna da dikkat edin.

Widget'larnz dorudan bir REST API'sinden veya uzak bir veritabanndan key-value iftleriyle alyorsa, yanl yapyorsunuz demektir. Baka bir deyile: i mantn (business logic) UI kodunuzla kartrmayn. Bu, kodunuzu test etmeyi, hata ayklamay ve nedenini bulmay ok daha zor hale getirecektir.

Repository Pattern Ne Zaman Kullanlr?

Uygulamanzn, uygulamann geri kalanndan izole etmek istediiniz yaplandrlmam verileri (unstructured data) (JSON gibi) dndren birok farkl u noktaya sahip karmak bir veri katman varsa, repository pattern ok kullanldr.

Daha genel olarak, repository pattern'in en uygun olduunu dndm birka kullanm rnei:

REST API'leri ile konumak
Yerel(local) veya uzak(remote) veritabanlaryla konumak (rn. Sembast, Hive, Firestore, vb.)
Cihaza zel API'lerle konumak (r. izinler, kamera, konum vb.)

Bu yaklamn byk bir yarar, kullandnz herhangi bir 3. taraf API'sinde son derece nemli deiiklikler olmas durumunda, yalnzca repository kodunuzu gncellemeniz gerekmesidir.

yleyse onlar nasl kullanacamz grelim!

rnek olarak, OpenWeatherMap API'sinden hava durumu verilerini eken basit bir Flutter uygulamasn inceleyeceiz.

API belgelerini okuyarak, JSON formatndaki baz yant verileri rnekleriyle birlikte API'yi nasl aracamz renebiliriz.

Repository pattern, tm a ve JSON seriletirme kodunu soyutlamak iin harikadr.

rnein, repository iin interface tanmlayan abstract(soyut) bir snf:

abstract class WeatherRepository {  Future<Weather> getWeather({required String city});}

WeatherRepository'nin yalnzca bir yntemi vardr, ancak daha fazlas da olabilir (rnein, tm CRUD ilemlerini desteklemek istiyorsanz).

nemli olan, repository'nin belirli bir ehir iin hava durumunu nasl alacamza dair bir szleme tanmlamamza izin vermesidir.

http veya dio gibi bir a istemcisi (networking client) kullanarak gerekli API arlarn yapan somut (concrete) bir snfla WeatherRepository'i implemente ederiz.

import 'package:http/http.dart' as http;class HttpWeatherRepository implements WeatherRepository {  HttpWeatherRepository({required this.api, required this.client});  // tm API ayrntlarn tanmlayan zel snf  final OpenWeatherMapAPI api;  // API'ye ar yapmak iin bir client  final http.Client client;  // yntemi soyut snfta uygular  Future<Weather> getWeather({required String city}) {    // TODO: istek gnder, yant ayrtr, Hava durumu nesnesini dndr veya hata at  }}

Tm bu uygulama ayrntlar, veri katmanyla (data layer) ilgili endielerdir ve uygulamann geri kalan bunlar umursamamal, hatta bilmemelidir.

JSON verilerini ayrtrma

Elbette , API yant verilerini (response data) ayrtrmak iin JSON seriletirme koduyla birlikte bir Weather model snf (veya entity ) tanmlamamz gerekecek:

class Weather {  factory Weather.fromJson(Map<String, dynamic> json) {    // TODO: JSON'u ayrtr ve dorulanm Hava Durumu nesnesini dndr  }}

JSON yant birok farkl alan ierebilirken, yalnzca kullanc arayznde (UI) kullanlacak olanlar ayrtrmamz gerektiini unutmayn.

JSON ayrtrma kodunu elle yazabilir veya Freezed gibi bir kod oluturma paketi kullanabiliriz . JSON seriletirme hakknda daha fazla bilgi edinmek iin Freezed Kullanarak Flutter'da JSON Nasl Ayrtrlr'a bakabilirsiniz.

Repository Initializing

Bir repository tanmladktan sonra, onu balatmann ve uygulamann geri kalan iin eriilebilir hale getirmenin bir yoluna ihtiyacmz var.

Bunu yapmak iin kullanlan szdizimi, setiiniz DI/state management (durum ynettimi) zmnze bal olarak deiir.

te get_it kullanan bir rnek :

import 'package:get_it/get_it.dart';GetIt.instance.registerLazySingleton<WeatherRepository>(  () => HttpWeatherRepository(api: OpenWeatherMapAPI(), client: http.Client(),);

te Riverpod paketinden bir salayc kullanan baka biri:

import 'package:flutter_riverpod/flutter_riverpod.dart';final weatherRepositoryProvider = Provider<WeatherRepository>((ref) {  return HttpWeatherRepository(api: OpenWeatherMapAPI(), client: http.Client());});

Flutter_bloc paketine dahilseniz , ite edeeri :

import 'package:flutter_bloc/flutter_bloc.dart';RepositoryProvider<WeatherRepository>(  create: (_) => HttpWeatherRepository(api: OpenWeatherMapAPI(), client: http.Client()),  child: MyApp(),))

Sonu ayndr: Repository'nizi bir kez balattnzda, ona uygulamanzn herhangi bir yerinden (widget'lar, bloklar, conroller vb.) eriebilirsiniz.

Abstract (soyut) ve concrete(somut) snflar

Repository olutururken sk sorulan bir soru udur: gerekten abstract bir snfa ihtiyacnz var m , yoksa sadece concrete bir snf oluturup tm iinizi halledebilir misiniz?

ki snfa giderek daha fazla yntem eklemek olduka skc olabileceinden, bu ok geerli bir endiedir:

abstract class WeatherRepository {  Future<Weather> getWeather({required String city});  Future<Forecast> getHourlyForecast({required String city});  Future<Forecast> getDailyForecast({required String city});}class HttpWeatherRepository implements WeatherRepository {  HttpWeatherRepository({required this.api, required this.client});  // tm API ayrntlarn tanmlayan zel snf  final OpenWeatherMapAPI api;  // API'ye ar yapmak iin client  final http.Client client;  Future<Weather> getWeather({required String city}) { ... }  Future<Forecast> getHourlyForecast({required String city}) { ... }  Future<Forecast> getDailyForecast({required String city}) { ... }}

Yazlm tasarmnda sklkla olduu gibi, cevap udur:

yleyse, her yaklamn baz artlarna ve eksilerine bakalm

Abstract (soyut) snflar kullanma:

Repository'mizin arayzn karklk olmadan tek bir yerden grebiliriz.

Repository'i tamamen farkl bir uygulama ile deitirebiliriz.
(rnein DioWeatherRepositoryyerine HttpWeatherRepository)

Daha fazla ortak kod.

Yalnzca concrete (somut) snflar kullanma:

Daha az ortak kod

"jump to reference" (referansa atla), respository methodlar yalnzca bir snfta bulunaca iin alr.

Repository adn deitirirsek farkl bir uygulamaya gemek daha fazla deiiklik gerektirir (ancak VSCode ile tm projedeki isimleri yeniden adlandrmak kolaydr).

Hangi yaklam kullanacamza karar verirken, kodumuz iin nasl test yazacamz da bulmalyz.

Repositoriy'lerle test yazma:

Abstract (soyut) snflar burada bize herhangi bir avantaj salamaz, nk Dart'ta tm snflar rtk bir arayze sahiptir (implicit interface) .

Bu, unu yapabileceimiz anlamna gelir:

// not: Dart'ta her zaman somut bir snf uygulayabilirizclass FakeWeatherRepository implements HttpWeatherRepository {  // hemen bir deer dndren sahte bir uygulama  Future<Weather> getWeather({required String city}) {     return Future.value(Weather(...));  }}

Baka bir deyile, testlerde repository'lerimize hazr yantlar vermek istiyorsak, abstract(soyut) snflar oluturmaya gerek yoktur.

Aslnda, mocktail gibi paketler bunu kendi avantajlarna kullanr ve biz de onlar u ekilde kullanabiliriz:

import 'package:mocktail/mocktail.dart';class MockWeatherRepository extends Mock implements HttpWeatherRepository {}final mockWeatherRepository = MockWeatherRepository();when(() => mockWeatherRepository.getWeather('London'))          .thenAnswer((_) => Future.value(Weather(...)));

Testlerinizi yazarken, depolarnza yukarda yaptmz gibi hazr yantlar verebilirsiniz.

Ancak baka bir seenek daha var ve bu, temel alnan veri kaynayla ilikilidir.

HttpWeatherRepository'nin Nasl tanmlandn hatrlayalm :

import 'package:http/http.dart' as http;class HttpWeatherRepository implements WeatherRepository {  HttpWeatherRepository({required this.api, required this.client});  // tm API ayrntlarn tanmlayan zel snf  final OpenWeatherMapAPI api;  // API'ye ar yapmak iin istemci  final http.Client client;  // yntemi soyut snfta uygular  Future<Weather> getWeather({required String city}) {    // TODO: istek gnder, yant ayrtr, Hava durumu nesnesini dndr veya hata at  }}

Bu durumda, HttpWeatherRepository constructor'na iletilen http.Client nesnesini taklit etmeyi seebiliriz. Bunu nasl yapabileceinizi gsteren rnek bir test:

import 'package:http/http.dart' as http;import 'package:mocktail/mocktail.dart';class MockHttpClient extends Mock implements http.Client {}void main() {  test('repository with mocked http client', () async {    // setup    final mockHttpClient = MockHttpClient();    final api = OpenWeatherMapAPI();    final weatherRepository =        HttpWeatherRepository(api: api, client: mockHttpClient);    when(() => mockHttpClient.get(api.weather('London')))        .thenAnswer((_) => Future.value(/* some valid http.Response */));    // run    final weather = await weatherRepository.getWeather(city: 'London');    // verify    expect(weather, Weather(...));  });}

Repository'lerin nasl test edileceini bulduktan sonra, abstract snflar hakkndaki ilk sorumuza geri dnelim.

Repository'ler abstract bir snfa ihtiya duymayabilir

Genel olarak, ayn arayze uyan birok uygulamaya ihtiyacnz varsa , abstract bir snf oluturmak mantkldr.

rnein, hem StatelessWidget hem de StatefulWidget Flutter SDK'da abstract snflardr , nk alt snflara ayrlmalar amalanr .

Ancak repository'ler ile alrken, belirli bir repository iin muhtemelen yalnzca bir implementasyona ihtiyacnz olacaktr.

Belirli bir repository iin yalnzca bir implementasyona ihtiyacnz olacak ve bunu tek, abstract(somut) bir snf olarak tanmlayabilirsiniz.

En Dk Ortak Payda

Her eyi bir arayzn arkasna koymak, sizi farkl yeteneklere sahip API'ler arasnda en dk ortak payday semeye itebilir.

Bir API veya backend, Ak tabanl (Stream-based) bir API ile modellenebilen gerek zamanl (realtime) gncellemeleri destekler.

Ancak saf REST kullanyorsanz (websocketler olmadan), yalnzca bir istek gnderebilir ve Future-based bir API ile en iyi modellenen tek bir yant (single response) alabilirsiniz.

Bununla baa kmak olduka kolaydr: sadece stream-based bir API kullann ve REST kullanyorsanz tek deerli bir ak dndrn.

Ancak bazen daha geni API farkllklar olabilir.

rnein, Firestore transaction'lar ve toplu yazmalar (batched writes) destekler. Bu tr API'ler , genel bir arabirimin arkasnda kolayca soyutlanamayacak ekilde, builder pattern' kullanr.

Repository'ler yatay olarak leklenir

Uygulamanz bydke, belirli bir repository'e giderek daha fazla method eklediinizi grebilirsiniz.

Bu, backend byk bir API yzeyine sahipse veya uygulamanz birok farkl veri kaynana (data source) balanrsa gerekleebilir.

Bu senaryoda, ilgili yntemleri bir arada tutarak birden ok repository oluturmay dnn. rnein, bir e-Ticaret uygulamas oluturuyorsanz, rn listeleme, alveri sepeti, sipari ynetimi, kimlik dorulama, deme vb. iin ayr repository'leriniz olabilir.

Basit tutun

Her zamanki gibi, ileri basit tutmak her zaman iyi bir fikirdir. Bu nedenle, API'lerinizi fazla dnmekten kendinizi alkoymayn.

zm

Veri katmannzn (data layer) tm uygulama ayrntlarn (rn. JSON seriletirme) gizlemek iin repository modelini kullann. Sonu olarak, uygulamanzn geri kalan (domain ve presentation-sunum katman) dorudan type-safe model snflar/entities ile ilgilenebilir. Ayrca kod tabannz, baml olduunuz paketlerdeki deiiklikleri bozmaya kar daha direnli hale gelecektir.

resource


Original Link: https://dev.to/gulsenkeskin/flutter-uygulama-mimarisi-repository-pattern-576j

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To