流行的Flutter应用架构比较

来源:codewithandrea.com 更新时间:2023-10-30 23:36

如果您需要帮助为您的 Flutter 应用程序选择最适合的项目结构,可以查看:

如果您想探索其他流行架构(如 MVP、MVVM 或 Clean Architecture)并了解它们如何与此处提出的架构相比较,可以阅读以下内容:

要了解 Riverpod 架构中每个层的更多信息,请阅读本系列中的其他文章:


开始新项目很有趣! 🎉

最初,推迟关于应用架构和良好的代码结构的决定可能很诱人。

但是,如果您的应用不仅仅是一个失败的副业项目,您将希望重新审视这些事情,并选择一个能够支持您的代码库随着它的增长而发展的应用架构。 🧱

在我的先前的文章中,我介绍了一种基于Riverpod包的应用架构,该架构基于四个主要层次: App architecture using data, domain, application, and presentation layers. Arrows show the dependencies between layers.
使用数据、领域、应用和展示层的应用程序架构。箭头显示了各层之间的依赖关系。我在许多不同的项目中使用了这种架构

但在您决定在下一个项目中尝试它之前,我想向您展示它与其他流行的架构相比如何。

而这正是这篇文章要讨论的内容。👇

现有架构概述

如果您研究这个话题,您可能会遇到诸如MVC、MVP、MVVM和Clean Architecture等术语。这些是早些时候引入的流行应用程序架构,旨在解决与Flutter今天面临的类似问题。

严格来说,MVC、MVP和MVVM是设计模式,而Clean Architecture定义了一组规则和原则,以帮助您构建任何复杂的软件系统。

虽然它们构建在的原则今天仍然非常相关,但它们并不是专为Flutter应用程序开发而定制的。

尽管如此,已经有很多尝试将它们引入Flutter世界的努力,成功程度不等。

流行的Flutter应用程序架构:Bloc和Stacked

最值得注意的是,Bloc架构Bloc库的普及而受到广泛采用,这个库被许多大公司所使用。它非常有见解,并为我们提供了一组严格的规则,用于构建Flutter应用程序的结构(这是一件好事!)。

另一个有前途的架构是Stacked架构,它基于Stacked包,并在很大程度上受到MVVM的启发。

它们都依赖于Provider,这是官方Flutter文档中推荐的状态管理包

虽然Bloc和Stacked都没有问题,但Provider的作者创建了Riverpod包,以“进行一些在其他情况下不可能的改进”(用他自己的话来说)。

随着时间的推移,我逐渐欣赏上了Riverpod的强大之处,它成为了依赖注入和状态管理的完整解决方案。但我的Riverpod架构与其他流行的架构相比如何呢?

与Clean Architecture的比较

Clean Architecture是由Robert C. Martin引入的,其表示如下图所示: The Clean Architecture

《干净架构》。来源和鸣谢:[《干净代码博客》](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) 虽然事物有不同的名称,但我们可以识别出一些相似的概念: - 实体; - 模型 - 用例; 服务 由于《干净架构》旨在独立于用户界面,它并不考虑从数据源到用户界面的单向数据流,这是许多现代应用架构的核心设计原则(包括Flutter和Web等)。

Comparison with the Clean Architecture

与Clean Architecture不同,它使用了一个接口适配器层,其中包括控制器、网关和呈现器。与此同时,在Riverpod架构中,存储库属于数据层,控制器属于呈现层。

同样,外层称为框架和驱动程序,包含UI和数据库。但在Riverpod架构中,它们位于相对的两端。

这并不是说Clean Architecture不好。但我发现它增加了一些思维负担,我更愿意使用一个更接近我日常用于Flutter应用开发的概念模型。

与MVC的比较

Model-View-Controller(MVC)是一个由3种类型的组件构成的软件设计模式:

  • Model:直接管理应用程序的数据、逻辑和规则
  • View:UI组件(小部件)
  • Controller:接受输入并将其转换为对模型或视图的命令 MVC Architecture
  • MVC 架构通常将太多逻辑集中在模型上,因此通常需要添加一个额外的服务层:MVC+S。

模型应该是响应式的(例如,使用 ChangeNotifier ),以便小部件在其更改时重建。

用户输入始终通过控制器传递,而不是直接通过模型。

与 Riverpod 架构相比,原始的 MVP 架构在各层之间的通信方式上有很大不同: Comparison with MVC Architecture 与MVC架构的比较

与MVVM的比较

Model-View-ViewModel(MVVM)模式被引入,以将应用程序的业务逻辑和呈现逻辑与用户界面(UI)分开。

通常以以下方式表示: MVVM Architecture 使用MVVM架构时,视图不能直接访问模型。

相反,视图模型处理用户输入并将模型中的数据转换,以便能够轻松呈现。

而视图模型通过使用观察者设计模式与视图进行数据绑定连接。

当从后端返回的数据与您需要显示的UI不匹配时,具有中间视图模型特别有用。 Comparison with MVVM Architecture 与MVVM架构相比,Riverpod架构易于进行比较:

  • 视图 → 小部件
  • 视图模型 → 控制器
  • 模型 → 模型 + 仓库 + 数据源

MVVM只是一种设计模式,上面的图表不包括任何关于数据层的概念。

实际上,服务和仓库被添加以封装数据访问和缓存,使MVVM与Riverpod架构非常相似。

与Bloc架构的比较

Bloc架构 页面包含了定义三个层次的图表:

  • 演示层

  • 业务逻辑

  • 数据(仓库和数据提供者) Bloc Architecture 来源与鸣谢:Bloc 架构。这与下面介绍的 Riverpod 架构类似:

  • 展示(UI)→ Widgets

  • 业务逻辑(Bloc)→ 控制器和服务

  • 数据(存储库)→ 存储库

  • 数据(数据提供者)→ 数据源

主要区别在于 blocs 可以依赖于其他 blocs 以对其状态更改作出反应,而 Riverpod 架构在控制器(负责管理小部件状态)和服务(负责管理应用程序状态)之间有更清晰的区分。

注意:使用 Bloc 时,状态更改始终表示为数据流。但 Riverpod 可以观察不同类型的数据(流、未来、StateNotifiers、ChangeNotifiers 等)。

总的来说,Bloc 架构与我提出的 Riverpod 架构非常接近,尽管我觉得它会迫使你编写太多类,反复不断(即使使用 Cubits,它们是 Bloc 的轻量级版本)。

与 Stacked 架构的比较

Stacked 架构(基于 Stacked 包)与 MVVM 类似(但不完全相同),由 3 个主要组件组成,可以很容易地映射到 Riverpod 架构:

  • 视图 → Widgets
  • 视图模型 → 控制器
  • 服务 → 服务

它还定义了一些关于您可以做什么和不能做什么的规则(更多信息请参阅此处)。

Stacked 提供了一个基础架构和一组有用的小部件(例如 ViewModelBuilder),您可以使用它们来"绑定"视图模型与视图,从而使您的生活更轻松,不必重新发明轮子。

视图模型本身是扩展 ChangeNotifier 的 Dart 类,它们具有响应式和非响应式变体。

主要区别在于 Stacked 基于 Provider,而 Riverpod 架构使用 Riverpod(显而易见 😅)。

但正如我们所说,Riverpod 为我们提供了构建强大架构所需的一切。

与Android应用架构的比较

直到现在,我都没有提到,但Android文档中也有一个有用的应用架构指南,它与我正在使用的架构非常相似。 Android App Architecture Android App Architecture 虽然这种架构涉及许多常见的Android组件(如活动、片段等),但在Flutter世界中,这些与小部件相同,而且在各层之间有密切的匹配: Comparison with Android App Architecture 在Android应用架构中,UI和数据层始终是必需的,而领域层是可选的。这是因为并非所有应用都具有1) 复杂的业务逻辑或2) 需要在多个视图模型之间重用的简单业务逻辑。同样,在Riverpod架构中,如果不需要应用层,可以省略它。

总的来说,我鼓励您阅读完整的Android指南,因为它详细描述了每个层在架构中的作用。

其他流行的架构

应用程序架构是基于使用设计模式而不是API的抽象构建的。因此,您可以在其他流行的状态管理包(如reduxMobX等)之上创建自己的应用程序架构。

甚至可以使用Flutter提供的开箱即用的功能(InheritedWidgetChangeNotifierValueListenableBuilder等)。

注意:GetX是一种流行的状态管理框架,声称可以完成所有工作。但我不会在这里详细介绍它,原因请参见这些 理由

最重要的是,您要在应用程序中定义明确的契约和边界。

在这方面,我非常喜欢这段引自eBay工程博客的引述:

我们相信,选择正确的工具或应用单一的设计模式,比建立应用程序中的独特特性和组件之间的明确契约和边界要不重要得多。没有边界,编写不随着应用程序复杂性增加而扩展的难以维护的代码将变得太容易。

结论

正如我们所看到的,Riverpod 架构与其他流行的架构有许多相似之处(以及一些差异)。

直到今天,我一直很高兴在各种Flutter应用程序中使用它