国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

現代化Flutter架構-Riverpod數據層

開發 架構
使用Repository模式來隱藏數據層的所有實現細節(如 JSON 序列化)。這樣,應用程序的其余部分(領域層和表現層)就可以直接處理類型安全的模型類/實體。您的代碼庫也將變得更有彈性,可以抵御您所依賴的包中出現的破壞性變化。

設計模式是幫助我們解決軟件設計中常見問題的有用模板。

說到應用程序架構,結構設計模式可以幫助我們決定如何組織應用程序的不同部分。

在這種情況下,我們可以使用Repository模式從各種來源(如后端 API)訪問數據對象,并將它們作為類型安全的實體提供給應用程序的領域層(即我們的業務邏輯的所在層)。

在本文中,我們將詳細了解Repository Pattern:

  • 它是什么,何時使用
  • 一些實際示例
  • 使用具體類或抽象類的實現細節及其取舍
  • 如何使用Repository測試代碼

我還將分享一個帶有完整源代碼的天氣應用程序示例。

準備好了嗎?讓我們開始吧!

什么是Repository Pattern?

要理解這一點,讓我們來看看下面的架構圖:

圖片圖片

在這種情況下,Repository位于數據層。它們的任務是:

  • 將領域模型(或實體)與數據層中數據源的實現細節隔離開來。
  • 將數據傳輸對象轉換為領域層可理解的有效實體
  • (可選)執行數據緩存等操作

?

上圖顯示的只是架構應用程序的多種可能方法之一。如果您采用不同的架構(如 MVC、MVVM 或簡潔架構),情況會有所不同,但概念是相同的。

還要注意的是,Widget屬于表現層,與業務邏輯或網絡代碼無關。

?

如果您的 widget 直接使用來自 REST API 或遠程數據庫的鍵值對,那您就做錯了。換句話說:不要將業務邏輯與用戶界面代碼混在一起。這會使你的代碼更難測試、調試和推理。

何時使用Repository Pattern?

如果您的應用程序有一個復雜的數據層,其中有許多不同的端點返回非結構化數據(如 JSON),而您希望將這些數據與應用程序的其他部分隔離開來,那么Repository Pattern就非常方便。

廣而言之,以下是我認為最適合使用Repository模式的幾種用例:

  • 與 REST API 通信
  • 與本地或遠程數據庫(如 Sembast、Hive、Firestore 等)通信
  • 與特定設備的 API(如權限、攝像頭、位置等)通信

這種方法的一大好處是,如果您使用的任何第三方應用程序接口發生重大變更,您只需更新版本庫代碼即可。

僅憑這一點,Repository就值得 100%使用。??

讓我們看看如何使用它們!??

實踐中的Repository Pattern

舉個例子,我構建了一個簡單的 Flutter 應用程序(這里是源代碼),從 OpenWeatherMap API 獲取天氣數據。

通過閱讀 API 文檔,我們可以找到如何調用 API,以及一些 JSON 格式響應數據的示例。

Repository模式非常適合抽象掉所有網絡和 JSON 序列化代碼。

例如,這里有一個抽象類,定義了Repository的接口:

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

上述 WeatherRepository 只有一個方法,但也可以有更多方法(例如,如果您想支持所有 CRUD 操作)。

重要的是,該Repository允許我們為,如何檢索給定城市的天氣定義一個接口。

我們需要用一個具體類來實現 WeatherRepository,該類可以使用網絡客戶端(如 http 或 dio)進行必要的 API 調用:

import 'package:http/http.dart' as http;

class HttpWeatherRepository implements WeatherRepository {
  HttpWeatherRepository({required this.api, required this.client});
  // custom class defining all the API details
  final OpenWeatherMapAPI api;
  // client for making calls to the API
  final http.Client client;

  // implements the method in the abstract class
  Future<Weather> getWeather({required String city}) {
    // TODO: send request, parse response, return Weather object or throw error
  }
}

所有這些實現細節都與數據層有關,應用程序的其他部分不應該關心或知道這些細節。解析 JSON 數據 當然,我們還必須定義氣象模型類(或實體),以及用于解析 API 響應數據的 JSON 序列化代碼:

class Weather {
  // TODO: declare all the properties we need
  factory Weather.fromJson(Map<String, dynamic> json) {
    // TODO: parse JSON and return validated Weather object
  }
}

請注意,雖然 JSON 響應可能包含許多不同的字段,但我們只需要解析將在用戶界面中使用的字段。我們可以手動編寫 JSON 解析代碼,或者使用代碼生成包(如 Freezed)。

在應用程序中初始化Repository

一旦定義了Repository,我們就需要一種方法來初始化它,并使應用程序的其他部分可以訪問它。執行此操作的語法會根據您選擇的 DI/狀態管理解決方案而改變。下面是一個使用 get_it 的示例:

import 'package:get_it/get_it.dart';

GetIt.instance.registerLazySingleton<WeatherRepository>(
  () => HttpWeatherRepository(api: OpenWeatherMapAPI(), client: http.Client(),
);

下面是另一個使用 Riverpod 軟件包中的提供程序的例子:

import 'package:flutter_riverpod/flutter_riverpod.dart';

final weatherRepositoryProvider = Provider<WeatherRepository>((ref) {
  return HttpWeatherRepository(api: OpenWeatherMapAPI(), client: http.Client());
});

如果你喜歡 flutter_bloc 軟件包,這里也有相應的功能:

import 'package:flutter_bloc/flutter_bloc.dart';

RepositoryProvider<WeatherRepository>(
  create: (_) => HttpWeatherRepository(api: OpenWeatherMapAPI(), client: http.Client()),
  child: MyApp(),
))

底層是一樣的:一旦初始化了Repository,就可以在應用程序的其他任何地方(Widget、模塊、Controller等)訪問它。

抽象類還是具體類?

在創建Repository時,一個常見的問題是:你真的需要一個抽象類嗎?這是個非常合理的問題,因為在兩個類中添加越來越多的方法可能會變得相當乏味:

abstract class WeatherRepository {
  Future<Weather> getWeather({required String city});
  Future<Forecast> getHourlyForecast({required String city});
  Future<Forecast> getDailyForecast({required String city});
  // and so on
}

class HttpWeatherRepository implements WeatherRepository {
  HttpWeatherRepository({required this.api, required this.client});
  // custom class defining all the API details
  final OpenWeatherMapAPI api;
  // client for making calls to the API
  final http.Client client;

  Future<Weather> getWeather({required String city}) { ... }
  Future<Forecast> getHourlyForecast({required String city}) { ... }
  Future<Forecast> getDailyForecast({required String city}) { ... }
  // and so on
}

正如軟件設計中經常出現的情況一樣,答案是:視情況而定。

因此,讓我們來看看每種方法的優缺點。

使用抽象類

優點:我們可以在一個地方看到Repository的接口,而不會感到雜亂無章。

優點:我們可以將Repository換成完全不同的實現(例如 DioWeatherRepository 而不是 HttpWeatherRepository),只需修改一行初始化代碼,因為應用程序的其他部分只知道 WeatherRepository。

缺點:當我們 “跳轉到引用 ”時,VSCode 會有點困惑,它會把我們帶到抽象類中的方法定義,而不是具體類中的實現。

缺點:更多模板代碼。

只使用具體類

優點:減少模板代碼。

優點:“跳轉到引用 ”只適用于一個類中的Repository方法。

缺點:如果我們更改了Repository名稱,那么切換到不同的實現就需要進行更多更改(不過使用 VSCode 對整個項目進行重命名很容易)。

在決定使用哪種方法時,我們還應考慮如何為代碼編寫測試。

使用Repository編寫測試代碼

在測試過程中,一個常見的要求是將網絡代碼換成模擬代碼或 “偽代碼”,這樣我們的測試就能運行得更快、更可靠。

然而,抽象類并不能給我們帶來任何優勢,因為在 Dart 中,所有類都有一個隱式接口。

這意味著我們可以這樣做:

// note: in Dart we can always implement a concrete class
class FakeWeatherRepository implements HttpWeatherRepository {

  // just a fake implementation that returns a value immediately
  Future<Weather> getWeather({required String city}) { 
    return Future.value(Weather(...));
  }
}

換句話說,如果我們打算在測試中模擬我們的Repository,就沒有必要創建抽象類。事實上,像 mocktail 這樣的包就利用了這一點,我們可以這樣使用它們:

import 'package:mocktail/mocktail.dart';

class MockWeatherRepository extends Mock implements HttpWeatherRepository {}

final mockWeatherRepository = MockWeatherRepository();
when(() => mockWeatherRepository.getWeather('London'))
          .thenAnswer((_) => Future.value(Weather(...)));

模擬數據源

在編寫測試時,可以模擬Repository并返回預制響應,就像我們上面做的那樣。但還有另一種方法,那就是模擬底層數據源。讓我們回顧一下 HttpWeatherRepository 是如何定義的:

import 'package:http/http.dart' as http;

class HttpWeatherRepository implements WeatherRepository {
  HttpWeatherRepository({required this.api, required this.client});
  // custom class defining all the API details
  final OpenWeatherMapAPI api;
  // client for making calls to the API
  final http.Client client;

  // implements the method in the abstract class
  Future<Weather> getWeather({required String city}) {
    // TODO: send request, parse response, return Weather object or throw error
  }
}

在這種情況下,我們可以選擇模擬傳遞給 HttpWeatherRepository 構造函數的 http.Client 對象。下面是一個測試示例,展示了如何做到這一點:

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本身還是模擬底層數據源。

了解了如何測試版本庫之后,讓我們回到最初關于抽象類的問題上來。

Repository可能不需要抽象類

一般來說,如果你需要許多符合相同接口的實現,創建抽象類是有意義的。

例如,在 Flutter SDK 中,StatelessWidget 和 StatefulWidget 都是抽象類,因為它們可以被子類化。

但在使用Repository時,您可能只需要一個給定Repository的實現。

您很可能只需要一個特定Repository的實現,您可以將其定義為一個單一的具體類。

最小公分母

把所有東西都放在接口后面,也會使你不得不在具有不同功能的 API 之間選擇最小公分母。

也許某個 API 或后端支持實時更新,這可以用基于 Stream 的 API 來建模。

但如果您使用的是純 REST(不含 websockets),您只能發送一個請求并獲得一個響應,這最好使用基于 Future 的 API 來建模。

處理這個問題非常簡單:只需使用基于流的 API,如果使用的是 REST,則只需返回包含一個值的流即可。

但有時會存在更廣泛的 API 差異。

例如,Firestore 支持事務和批量寫入。這類 API 在源碼中使用了構建器模式,而這種模式不容易抽象為通用接口。

如果遷移到不同的后端,新的 API 很可能會有很大不同。換句話說,面向未來的當前應用程序接口往往不切實際,而且會適得其反。

Repository橫向擴展

隨著應用程序的增長,您可能會發現自己向給定的Repository中添加的方法越來越多。

如果您的后端有很大的 API 列表,或者如果您的應用程序連接到許多不同的數據源,就可能出現這種情況。

在這種情況下,可以考慮創建多個Repository,將相關的方法放在一起。例如,如果您正在構建一個電子商務應用程序,您可以為產品列表、購物車、訂單管理、身份驗證、結賬等創建單獨的Repository。

保持簡單

與往常一樣,保持簡單總是個好主意。因此,不要對應用程序接口想得太多。

您可以根據您需要使用的 API 來構建您的版本庫接口模型,然后就可以收工了。如果需要,您可以隨時重構。??

結論

如果我想讓你從這篇文章中得到什么啟發,那就是:使用Repository模式來隱藏你的代碼:

使用Repository模式來隱藏數據層的所有實現細節(如 JSON 序列化)。這樣,應用程序的其余部分(領域層和表現層)就可以直接處理類型安全的模型類/實體。您的代碼庫也將變得更有彈性,可以抵御您所依賴的包中出現的破壞性變化。

如果說有什么收獲的話,我希望這篇概述能鼓勵您更清晰地思考應用程序架構,以及擁有邊界清晰的獨立表現層、應用層、領域層和數據層的重要性。

本文翻譯自:https://codewithandrea.com/articles/flutter-repository-pattern/

責任編輯:武曉燕 來源: 群英傳
相關推薦

2025-08-08 07:18:00

CIOIT架構IT服務管理

2023-06-25 09:04:12

數字企業架構EA

2023-02-08 11:07:56

數字時代數字運營模式

2020-08-05 07:00:00

數據架構工具技術

2024-01-23 15:21:14

2021-04-13 16:13:38

大數據教育科學

2013-03-22 10:27:40

企業再現代化IBM論壇2013

2022-07-26 06:57:07

數據管道端點API

2018-06-05 13:43:49

數據基礎設施

2015-10-29 14:35:21

移動設備現代化

2022-07-11 05:34:19

云原生應用程序

2025-10-10 08:00:00

2017-11-23 05:50:14

2019-08-30 08:23:47

基礎架構IT架構數據備份

2017-11-06 14:48:01

大數據法醫犯罪

2015-12-24 10:33:31

數據中心現代數據中心

2023-08-18 08:07:37

2020-06-05 14:16:05

醫藥
點贊
收藏

51CTO技術棧公眾號

一区二区传媒有限公司| 周于希免费高清在线观看| 久久99精品国产.久久久久久| 欧美最猛性xxxxx亚洲精品| 欧美理论影院| 精品国产免费人成电影在线观看四季| 一级毛片在线看| 亚洲精品欧美在线| 簧片在线免费看| 久久精品一区二区三区av| 春日野结衣av| 久久精品亚洲一区二区三区浴池| 色欲色香天天天综合网www| 不卡在线观看av| www.爱色av.com| 91天堂素人约啪| 国产亚洲精品网站| 国产喷白浆一区二区三区| 天天影视综合色| 亚洲免费观看高清完整| 日本视频三区| 亚洲h动漫在线| 国产尤物视频在线| 欧美日本视频在线| 性国产高清在线观看| 精品国产乱码久久久久久蜜臀| 欧美xxxx少妇| 亚洲偷熟乱区亚洲香蕉av| 国产精品伦一区二区| 久久夜色精品国产| 日韩成人久久| 国产精品av网站| 综合精品久久| 亚洲精品国产一区| 99精品视频在线免费观看| 先锋影音资源综合在线播放av| 亚洲一区免费观看| 麻豆av在线导航| 亚洲视频综合网| 欧美一级一片| 91欧美精品成人综合在线观看| 欧美激情综合| 亚洲欧美日韩在线综合| 91啪九色porn原创视频在线观看| 上原亚衣加勒比在线播放| 精品久久久久久亚洲国产300| 免费日本一区二区三区视频| 亚洲男人天堂古典| 综合激情久久| 亚洲已满18点击进入在线看片| 亚洲精品偷拍| 黄色大片中文字幕| 偷拍一区二区三区四区| av网站免费在线观看| www.欧美免费| 99久久精品网站| 日本三级中文字幕在线观看| 国产精品美女久久久久久久网站| 狠狠狠综合7777久夜色撩人| 亚洲欧美制服另类日韩| 久草精品在线| 男人的天堂成人| 亚洲影视在线播放| 欧美aaaaa性bbbbb小妇| 98精品国产高清在线xxxx天堂| 欧美日韩福利| 人妻有码中文字幕| 欧美天堂亚洲电影院在线播放| 免费高清视频在线一区| 国产欧美一区二区三区久久| 激情综合一区二区三区| 操碰在线免费| 在线视频日本亚洲性| 欧美在线免费| 可以在线看的黄色网址| 在线免费观看成人短视频| 亚洲综合资源| 欧美少妇一区| 亚洲成av人**亚洲成av**| segui88久久综合9999| 欧美一区在线直播| 久久电影网电视剧免费观看| 日韩欧美亚洲一区| 中文字幕日韩视频| 亚洲激情网站| 视频免费裸体网站| 一区二区在线免费视频| 在线日韩欧美| 天天噜天天色| 久久综合伊人77777| 日韩不卡一区二区三区 | 亚洲一卡二卡三卡| 一区二区三区小说| 日韩一区精品| 久久久久久亚洲精品不卡4k岛国 | 亚洲欧美丝袜| 精品国产福利在线| 五月亚洲婷婷| 中文字幕精品一区日韩| 欧美日韩亚洲综合在线 | 午夜久久美女| 亚洲jizzjizz妇女| 在线a欧美视频| 免费亚洲电影在线| av网站在线免费观看| 国产精品免费小视频| 欧美国产精品一区二区三区| 国产传媒在线观看| 看欧美日韩国产| 日本高清免费不卡视频| 波多野结衣在线观看一区二区三区| 久久亚洲中文字幕无码| 日韩成人xxxx| 首页欧美精品中文字幕| 在线免费观看的av网站| 成人午夜在线视频一区| 亚洲精品日日夜夜| 99ri日韩精品视频| 国产一区二区视频免费在线观看| 亚洲夜晚福利在线观看| 国内精品久久久久影院薰衣草| 羞羞视频在线观看免费| 激情视频一区二区| 欧美日韩免费不卡视频一区二区三区| 日本一区二区在线看| 米奇777在线影院线| 欧美国产日韩精品| 国产色一区二区| 1313精品午夜理伦电影| 虎白女粉嫩尤物福利视频| 久久亚洲精品国产亚洲老地址| 成人午夜碰碰视频| 欧美男男gaygay1069| 天天夜碰日日摸日日澡性色av| 色久欧美在线视频观看| www久久久久| 免费成人蒂法| 精品女厕厕露p撒尿| 91久久精品美女| 在线观看亚洲精品视频| 极品尤物久久久av免费看| 香蕉视频在线免费看| 欧美日韩一区二区三区在线视频 | 欧美黑人xxx| 日韩一区在线免费观看| 老牛影视av一区二区在线观看| 亚洲最大成人在线观看| 日本高清视频一区| 欧美天堂在线观看| 在线亚洲一区| 欧美四级在线| 欧美久久久久久久久久久久久久| 亚洲一区二区久久久| 91免费精品国自产拍在线不卡| 国产伦精品一区二区三区免费优势 | 国产伦精品一区二区三区视频免费 | 男人天堂久久| 中文字幕 91| 成人欧美在线观看| 5858s免费视频成人| 久久9热精品视频| 国产精品日本一区二区三区在线| 超碰影院在线观看| 成人精品视频99在线观看免费 | 狠狠狠综合7777久夜色撩人| 麻豆精品蜜桃一区二区三区| 精品一区精品二区| 国产精品无码永久免费888| 亚洲欧洲美洲一区二区三区| 最新av在线播放| 国产性xxxx18免费观看视频| 国产免费一区二区三区在线能观看 | 欧美婷婷六月丁香综合色| 日本成人在线一区| 日本免费在线一区| 蜜桃av成人| 在线天堂一区av电影| 97精品国产97久久久久久免费| 欧美日韩人人澡狠狠躁视频| 三级精品在线观看| 精品视频一二| 成人午夜电影在线观看| 免费日韩在线观看| 国产成人精品亚洲精品| 日韩一区二区三区三四区视频在线观看 | 金瓶狂野欧美性猛交xxxx| 久久久久久久少妇| 国产乱码精品一区二区三区不卡| 一本一本久久a久久精品牛牛影视 一本色道久久综合亚洲精品小说 一本色道久久综合狠狠躁篇怎么玩 | 97国产精品久久| 91精品国产乱| 国产欧美日韩三区| 视频一区二区三区在线| 丁香五月缴情综合网| 国产婷婷视频在线| 99在线免费观看| 国产欧美123| 国产精品免费一区二区三区四区| 久久手机精品视频| 91精品国产91久久久久久最新毛片|