开始新项目很有趣!🎉 最初,人们可能会倾向于推迟有关应用程序架构和良好代码结构的任何决定。 但如果你的应用程序不仅仅是一个失败的副项目,你就会想重新审视并选择一个能够支持你的代码库不断增长的应用程序架构。🧱 在 CODE WITH ANDREA:使用 Riverpod 的 Flutter 应用架构介绍 文章中,介绍了基于 Riverpod 包的应用程序架构,明确了该架构包含四层:数据层、 领域层、 应用层、展示层。 但是在您决定在下一个项目中尝试它之前,我想向您展示它与其他流行架构的比较。这正是本文的主题。👇

现有架构概述
如果你研究这个主题,你可能会遇到诸如MVC、MVP、MVVM和Clean Architecture之类的术语。这些都是很早以前就引入的流行应用程序架构,用于解决与我们今天在 Flutter 中面临的类似问题。
严格来说,MVC、MVP 和 MVVM 是设计模式,而清晰架构定义了一组规则和原则来帮助您构建任何复杂的软件系统。
虽然它们所依据的原则在今天仍然非常重要,但它们并不适合Flutter 应用开发。 尽管如此,人们还是进行了许多尝试将它们带入 Flutter 世界,并取得了不同程度的成功。
流行的 Flutter 应用架构:Bloc 和 Stacked
最值得注意的是, Bloc 架构 得到了一些良好的采用,这主要归功于 Bloc 库的流行,它被各大公司使用。它 非常固执己见 ,为我们如何构建 Flutter 应用程序提供了一套严格的规则(这是一件好事!)。
另一个很有前途的是 Stacked Architecture,它基于 Stacked 包并且很大程度上受到 MVVM 的启发。
它们都依赖于 Provider,这是 Flutter 官方文档中推荐的状态管理包。
虽然 Bloc 和 Stacked 都没有问题,但 Provider 的作者创建了 Riverpod 包来“做出一些原本不可能实现的改进”(用他自己的话说)。
随着时间的推移,我逐渐意识到 Riverpod 作为 依赖注入 和 状态管理的完整解决方案的强大功能。但我的 Riverpod 架构与其他流行架构相比如何?
与 Clean Architecture 的比较
清洁架构 (Clean Architecture)由 Robert C. Martin 提出,如下图所示:

虽然事物的名称不同,但我们可以识别出一些相似的概念:
- 实体 → 模型
- 用例 → 服务
由于 Clean Architecture 的设计目的是为了独立于 UI,因此它不考虑从数据源到 UI 的单向数据流,这是许多现代应用程序架构(Flutter 和 Web 均是如此)的核心设计原则。

而是使用包含Controller、网关和演示者的接口适配层。同时,在 Riverpod 架构中,Repository属于数据层,Controller属于展示层。
同样,外层称为框架和驱动程序,包含 UI 和 DB。但在 Riverpod 架构中,它们处于相反的两端。
这并不是说 Clean Architecture 不好。但我发现它增加了一些心理负担,我宁愿使用更接近我日常用于 Flutter 应用开发的概念模型。
与 MVC 的比较
模型视图Controller (MVC) 是一种由 3 种类型的组件组成的软件设计模式:
Model(模型):直接管理应用程序的数据、逻辑和规则View(视图):UI 组件(Widget)Controller(Controller):接受输入并将其转换为模型或视图的命令

MVC 通常会用过多的逻辑来加重模型负担,并且通常会添加一个额外的服务层:MVC+S。
该模型应该是反应性的(例如,使用ChangeNotifier),以便Widget在其发生变化时重建。
用户输入总是通过Controller而不是直接通过模型。
与 Riverpod 架构相比,vanilla MVC 在各层之间的通信方式上有很大的差异:

与 MVVM 的比较
引入模型-视图-视图模型 (MVVM) 模式是为了将应用程序的业务和表示逻辑与其用户界面 (UI) 分离。
它通常表示如下:

当使用 MVVM 时,视图不能直接访问模型。
相反,视图模型处理用户输入并转换模型中的数据,以便可以轻松呈现。
并且视图模型通过使用观察者设计模式的数据绑定连接到视图。
当后端返回的数据不能很好地映射到您需要显示的 UI 时,拥有中间视图模型特别有用。

从这个方面来说,很容易将 MVVM 与 Riverpod 架构进行比较:
- 视图 → Widget
- 视图模型 → Controller
- 模型 → 模型 + Repository + 数据源
MVVM只是一种设计模式,上面的图并不包含后面任何数据的概念。
在实践中,添加了服务和Repository来封装数据访问和缓存,使得 MVVM 与 Riverpod 架构非常相似。
与 Bloc 架构的比较
Bloc架构页面包含此图表,其中定义了三个层:
Presentation展示Business Logic业务逻辑Data (Repository & Data Provider)数据(Repository和数据提供者)

这与这里介绍的 Riverpod 架构类似:
- 展示 (UI) → Widget
- 业务逻辑 (Bloc) → Controller和服务
- 数据(Repository)→ Repository
- 数据(数据提供者)→ 数据源
主要区别在于,块可以依赖于其他块来对其状态变化做出反应,而 Riverpod 架构在Controller(管理Widget状态)和服务(管理应用程序状态)之间有更明确的区分。
注意:使用 Bloc 时,状态变化始终表示为数据流。但 Riverpod 可以监视不同类型的数据(Streams、Futures、StateNotifiers、ChangeNotifiers 等)。
总体而言,Bloc 架构与我提出的 Riverpod 架构非常接近 - 尽管我觉得它迫使你一遍又一遍地编写太多的类(即使使用 Cubits,它是 Bloc 的轻量级版本)。
与堆叠架构的比较
Stacked 架构(基于Stacked包)与 MVVM 类似(但不完全相同),由 3 个主要部分组成,可以很容易地映射到 Riverpod 架构:
- View → Widgets
- ViewModel → Controller
- Service → Service
它还定义了一些关于你可以做什么和不能做什么的规则(更多信息请点击此处)。
Stacked 提供了一个基础架构和一组广泛有用的Widget(例如ViewModelBuilder),您可以使用它们将 ViewModel 与 View“绑定”,让您的生活更轻松,这样您就不必重新发明轮子了。
ViewModels 本身是扩展的 Dart 类ChangeNotifier,并且带有反应式和非反应式变体。
主要区别在于 Stacked 基于 Provider,而 Riverpod 架构使用 Riverpod(显然😅)。
但正如我们所说,Riverpod 为我们提供了构建强大架构所需的一切。
与Android应用程序架构的比较
我到现在还没有提到这一点,但 Android 文档中也有一个有用的应用程序架构指南,与我正在使用的非常相似。

虽然该架构引用了许多常见的 Android 组件(例如Activities、Fragments等),但它们与Flutter 世界中的Widget相同,并且各层之间也非常接近:

在 Android 应用架构中,UI 层和数据层始终是必需的,而域层则是可选的。这是因为并非所有应用都有 1) 复杂的业务逻辑或 2) 需要由多个视图模型重用的简单业务逻辑。同样,在 Riverpod 架构中,如果不需要,我们可以省略应用层。
总的来说,我鼓励你阅读整个 Android 应用架构指南,因为它详细描述了每一层的作用。
其他流行架构
应用程序架构基于使用设计模式而非 API实现的抽象。因此,您可以在其他流行的状态管理包(如redux、MobX等)之上创建自己的应用程序架构。
您甚至可以使用 Flutter 提供的开箱即用功能(InheritedWidget、ChangeNotifier、ValueListenableBuilder及其朋友)。
注意:GetX 是一个流行的状态管理框架,号称无所不能。但出于一些 很好 的 理由,我不会在这里介绍它。
最终,最重要的是在您的应用程序中定义明确的契约和界限。
在这方面,我非常喜欢eBay 工程博客的这句话:
我们认为,选择正确的工具或应用单一的设计模式远不如在应用程序中的独特功能和组件之间建立清晰的契约和界限重要。如果没有界限,随着应用程序复杂性的增加,代码扩展就会变得困难,且难以维护。
结论
正如我们所见,Riverpod 架构与其他流行架构有许多共同之处(也有一些不同之处)。
参考资料
文档信息
- 本文作者:Bob.Zhu
- 本文链接:https://home.mytool.group/2024/08/16/01-comparison-flutter-app-architectures/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
