本页面介绍了架构最佳实践、它们为何重要以及我们是否推荐将它们用于您的 Flutter 应用程序。您应将这些建议视为建议,而非硬性规定,并应根据您应用程序的独特需求进行调整。

本页面上的最佳实践有优先级之分,反映了 Flutter 团队对其推荐的强度。

  • 强烈推荐:如果您开始构建新应用程序,应始终实施此建议。您应认真考虑重构现有应用程序以实施此实践,除非这样做与您当前的方法根本冲突。
  • 推荐:此实践很可能会改进您的应用程序。
  • 有条件推荐:此实践在某些情况下可以改进您的应用程序。

关注点分离

您应该将应用程序划分为 UI 层和数据层。在这些层内,您应该根据职责将逻辑进一步划分为类。




建议描述

使用定义清晰的数据层和 UI 层。

强烈推荐

关注点分离是最重要的架构原则。数据层向应用程序的其余部分公开应用程序数据,并包含应用程序中的大部分业务逻辑。UI 层显示应用程序数据并监听用户的用户事件。UI 层包含独立的 UI 逻辑和 Widget 类。


在数据层中使用存储库模式。

强烈推荐

存储库模式是一种软件设计模式,它将数据访问逻辑与应用程序的其余部分隔离开。它在应用程序的业务逻辑和底层数据存储机制(数据库、API、文件系统等)之间创建了一个抽象层。实际上,这意味着创建存储库类和服务类。


在 UI 层中使用 ViewModel 和 View。(MVVM)

强烈推荐

关注点分离是最重要的架构原则。这种特殊的划分使您的代码出错的可能性大大降低,因为您的 Widget 仍然是“哑巴”的。


使用 ChangeNotifierListenable 来处理 Widget 更新。

有条件推荐

ChangeNotifier API 是 Flutter SDK 的一部分,是一种方便的方式来让您的 Widget 观察 ViewModel 中的更改。


有许多选项可用于处理状态管理,最终的决定取决于个人偏好。阅读我们的 ChangeNotifier 推荐其他流行选项

不要在 Widget 中放置逻辑。

强烈推荐

逻辑应封装在 ViewModel 的方法中。视图应包含的唯一逻辑是

  • 简单的 if 语句,用于根据 ViewModel 中的标志或可空字段显示和隐藏 Widget

  • 依赖 Widget 计算的动画逻辑

  • 基于设备信息(如屏幕大小或方向)的布局逻辑。

  • 简单的路由逻辑


使用领域层。

有条件推荐

只有当您的应用程序具有超出 ViewModel 复杂度的逻辑,或者您发现自己在 ViewModel 中重复逻辑时,才需要领域层。在非常大的应用程序中,用例很有用,但在大多数应用程序中,它们会增加不必要的开销。


在具有复杂逻辑要求的应用程序中使用。


数据处理

小心处理数据可使您的代码更易于理解,出错的可能性更小,并防止创建格式错误或意外的数据。





建议描述

使用单向数据流。

强烈推荐

数据更新应仅从数据层流向 UI 层。UI 层中的交互被发送到数据层进行处理。


使用 Commands 来处理用户交互事件。

推荐

Commands 可防止您的应用程序出现渲染错误,并标准化 UI 层将事件发送到数据层的方式。请阅读 架构案例研究 中的 Commands 部分。


使用不可变数据模型。

强烈推荐

不可变数据对于确保任何必要的更改仅在适当的位置(通常是数据层或领域层)发生至关重要。由于不可变对象在创建后无法修改,因此您必须创建新实例来反映更改。此过程可防止 UI 层中的意外更新,并支持清晰的单向数据流。


使用 freezed 或 built_value 生成不可变数据模型。

推荐

您可以使用软件包来帮助生成数据模型中有用的功能,例如 freezedbuilt_value。这些可以生成常见的模型方法,如 JSON 序列化/反序列化、深度相等性检查和 copy 方法。如果您有很多模型,这些代码生成包会显著增加应用程序的构建时间。


创建单独的 API 模型和领域模型。

有条件推荐

使用单独的模型会增加冗余,但可以防止 ViewModel 和用例中的复杂性。


在大型应用程序中使用。


应用程序结构

组织良好的代码对应用程序本身以及参与代码的团队都有益。




建议描述

使用依赖注入。

强烈推荐

依赖注入可防止您的应用程序拥有全局可访问的对象,从而降低代码出错的可能性。我们建议您使用 provider 软件包来处理依赖注入。


使用 go_router 进行导航。

推荐

Go_router 是编写 90% Flutter 应用程序的首选方式。有些特定用例 go_router 无法解决,在这种情况下,您可以使用 Flutter Navigator API 直接使用,或尝试在 pub.dev 上找到的其他软件包。


为类、文件和目录使用标准化的命名约定。

推荐

我们建议为类命名,以反映它们所代表的架构组件。例如,您可能有以下类

  • HomeViewModel
  • HomeScreen
  • UserRepository
  • ClientApiService

为了清晰起见,我们不建议使用可能与 Flutter SDK 对象混淆的名称。例如,您应该将共享 Widget 放在名为 ui/core/ 的目录中,而不是名为 /widgets 的目录中。


使用抽象存储库类

强烈推荐

存储库类是应用程序中所有数据的真实来源,并促进与外部 API 的通信。创建抽象存储库类允许您创建不同的实现,这些实现可用于不同的应用程序环境,例如“开发”和“暂存”。



测试

良好的测试实践使您的应用程序具有灵活性。它还使添加新逻辑和新 UI 变得简单且风险较低。

建议描述

单独且一起测试架构组件。

强烈推荐

* 为每个服务、存储库和 ViewModel 类编写单元测试。这些测试应单独测试每个方法的逻辑。

  • 为视图编写 Widget 测试。测试路由和依赖注入尤其重要。


创建测试的模拟(并编写利用模拟的代码)。

强烈推荐

模拟(Fakes)不像关注任何给定方法的内部工作方式,更关注输入和输出。如果您在编写应用程序代码时考虑这一点,您将被迫编写具有清晰定义的输入和输出的模块化、轻量级的函数和类。



#
  • 代码和模板
    • Compass app 源代码 - 一个功能齐全、健壮的 Flutter 应用程序的源代码,实现了许多这些建议。
    • very_good_cli - 由 Flutter 专家 Very Good Ventures 创建的 Flutter 应用程序模板。此模板会生成类似的应用程序结构。
  • 文档
  • 工具
    • Flutter 开发者工具 - DevTools 是 Dart 和 Flutter 的性能和调试工具套件。
    • flutter_lints - 一个包含 Flutter 团队推荐的 Flutter 应用 lint 的软件包。使用此软件包可在团队中推广良好的编码实践。

反馈

#

由于本网站的该部分正在不断发展,我们欢迎您的反馈