为什么(通常)在 BLoC 模式上有一个存储库层?

Che*_*ong 6 flutter

我是 Flutter 的新手,刚刚从阅读有关 Flutter 的教程中听说了 BLoC 概念。从本教程中,我第一次听说 BLoC。但是我在这篇文章中也看到了一个名为“Repository”的文件。基本上数据流是这样的:

Web API --> Api Provider --> Repository --> BLoC --> Widget
Run Code Online (Sandbox Code Playgroud)

我不明白的是,为什么需要 Repository 层,因为当我查看存储库文件时,它基本上只是返回 API Provider 的 Future 结果?我很好奇并尝试进一步搜索,我看到互联网上一些人的编码模式也有一个 Repository 层。

在原始文章中,API Provider 做了一切。它调用 get 请求,等待 Future 解析,将 JSON 数据转换为适当的模型,并返回用 Future 括起来的模型。

class ApiProvider {
  Future<ItemModel> fetchMovieList() async {
    final response = await client.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey");
    if (response.statusCode == 200)
      return ItemModel.fromJson(json.decode(response.body));
    else
      throw Exception('Failed to load post');
  }
}

class Repository {
  ApiProvider _api = ApiProvider();

  Future<ItemModel> fetchMovieList() => _api.fetchMovieList(); // why?
}

class Bloc {
  Repository _repository = Repository();
  final _moviesFetcher = PublishSubject<ItemModel>();
  Observable<ItemModel> get allMovies => _moviesFetcher.stream;

  fetchAllMovies() async {
    ItemModel itemModel = await 
    _repository.fetchAllMovies();
    _moviesFetcher.sink.add(itemModel);
  }
}
Run Code Online (Sandbox Code Playgroud)

目前我修改它,以便 Api Provider 返回纯 Future,其中 Repository 实现.then()并将响应转换为适当的数据,但我倾向于避免 await,因为在 React Native 中 await 会导致应用程序看起来没有响应。我还将错误检查移到 BLoC 中。

class ApiProvider {
  Future fetchMovieList() => client.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey");
}

class Repository {
  ApiProvider _api = ApiProvider();
  Future<ItemModel> fetchMovieList() => _api.fetchMovieList().then(response => ItemModel.fromJson(json.decode(response.body));
}

class Bloc {
  Repository _repository = Repository();
  final _moviesFetcher = PublishSubject<ItemModel>();
  Observable<ItemModel> get allMovies => _moviesFetcher.stream;

  fetchAllMovies() async => _repository.fetchPopularMovies().then((response) => _moviesFetcher.sink.add(response))
  .catchError((onError) => throw Exception("Failed to load post $onError"));
}
Run Code Online (Sandbox Code Playgroud)

但是,我仍然觉得这是证明需要这个 Repository 层的一种延伸。如果可以,我想让它像这样:

class ApiProvider {
  Future<ItemModel> fetchMovieList() => client.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey")
    .then(response => ItemModel.fromJson(json.decode(response.body));
}

class Bloc {
  ApiProvider _api = ApiProvider();
  final _moviesFetcher = PublishSubject<ItemModel>();
  Observable<ItemModel> get allMovies => _moviesFetcher.stream;

  fetchAllMovies() async => _api.fetchPopularMovies().then((response) => _moviesFetcher.sink.add(response))
  .catchError((onError) => throw Exception("Failed to load post $onError"));
}
Run Code Online (Sandbox Code Playgroud)

并完全摆脱 Repository 层。我并不是想说 Repository 层是不必要的,但现在我不知道 Repository 层试图解决什么模式问题。我只想知道为什么首先有一个 Repository 层以及 Repository 在现实世界中的重要用例是什么。我知道这个问题可能会被标记为可以引发讨论而不是直接回答的问题。但我相信对这个问题有某种狭隘的答案。当我尝试在 Internet 上进行搜索时,我只是找不到它(搜索结果与“存储库”术语的其他用法混淆,例如 git 和 subversion)。

Che*_*ong 6

好吧,别提了。我发现这篇优秀的文章解释了基本上 Repository 是抽象数据的来源,无论是来自磁盘缓存、云还是其他来源。工厂将根据每个来源的可用性决定使用哪种来源。来电者只需要通过一扇门。因为上面的教程只有一个来源(API/云),那一刻对我来说似乎没什么用。


小智 6

这是对原因的精彩总结。这是完全有道理的。这是来自 BLoC 文档,其中详细介绍了使用存储库层的天气应用程序教程(请参阅此处查看完整文章)。

“我们的存储库层的目标是抽象我们的数据层并促进与 bloc 层的通信。在这样做时,我们的代码库的其余部分仅依赖于我们的存储库层公开的函数,而不是特定的数据提供程序实现。这使我们能够在不破坏任何应用程序级代码的情况下更改数据提供者。例如,如果我们决定从metaweather迁移,我们应该能够创建一个新的API客户端并将其交换出来,而无需更改存储库或应用程序层。”

我要去争取!