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

本页中的最佳实践具有优先级,这反映了 Flutter 团队的推荐程度。

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

关注点分离

您应该将应用分为 UI 层和数据层。在这些层内,您应该根据职责将逻辑进一步分离到不同的类中。




建议描述

使用明确定义的数据层和 UI 层。

强烈推荐

关注点分离是最重要的架构原则。数据层将应用数据暴露给应用的其余部分,并包含应用中的大部分业务逻辑。UI 层显示应用数据并监听来自用户的用户事件。UI 层包含用于 UI 逻辑和部件(widget)的单独类。


在数据层中使用 Repository 模式。

强烈推荐

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


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

强烈推荐

关注点分离是最重要的架构原则。这种特定的分离使得您的代码更不容易出错,因为您的部件(widget)保持“愚笨”(dumb)状态。


使用 ChangeNotifierListenable 处理部件更新。

有条件推荐

ChangeNotifier API 是 Flutter SDK 的一部分,是一种方便让您的部件(widget)观察 ViewModel 中变化的方法。


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

不要将逻辑放入部件(widget)中。

强烈推荐

逻辑应封装在 ViewModel 的方法中。视图应仅包含以下逻辑:

  • 基于 ViewModel 中的标志或可为空字段来显示和隐藏部件(widget)的简单 if 语句

  • 依赖部件(widget)计算的动画逻辑

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

  • 简单的路由逻辑


使用领域层。

有条件推荐

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


用于具有复杂逻辑要求的应用。


数据处理

谨慎处理数据可使您的代码更易于理解、减少出错,并防止创建格式错误或意外的数据。





建议描述

使用单向数据流。

强烈推荐

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


使用 Command 处理用户交互事件。

推荐

Command 可以防止应用中出现渲染错误,并规范 UI 层向数据层发送事件的方式。在架构案例研究中阅读有关 Command 的内容。


使用不可变数据模型。

强烈推荐

不可变数据对于确保所有必要的更改只发生在正确的位置至关重要,通常是数据层或领域层。由于不可变对象在创建后不能被修改,您必须创建一个新实例来反映更改。此过程可防止 UI 层中的意外更新,并支持清晰的单向数据流。


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

推荐

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


创建独立的 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 的目录中。


使用抽象 Repository 类

强烈推荐

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



测试

良好的测试实践使您的应用更灵活。它也使得添加新逻辑和新 UI 变得简单且风险较低。

建议描述

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

强烈推荐

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

  • 为视图编写部件(widget)测试。测试路由和依赖注入尤为重要。


为测试创建伪造对象(fake),并编写利用伪造对象的代码。

强烈推荐

伪造对象(fake)与其说关注任何给定方法的内部工作原理,不如说关注输入和输出。如果您在编写应用程序代码时考虑到这一点,您将被迫编写具有明确输入和输出的模块化、轻量级函数和类。



#
  • 代码和模板
    • 指南针应用源代码 - 实现了许多这些建议的、功能齐全、健壮的 Flutter 应用程序的源代码。
    • very_good_cli - 由 Flutter 专家 Very Good Ventures 制作的 Flutter 应用程序模板。此模板生成相似的应用结构。
  • 文档
  • 工具
    • Flutter 开发工具 - DevTools 是一套用于 Dart 和 Flutter 的性能和调试工具。
    • flutter_lints - 一个包含 Flutter 团队推荐的 Flutter 应用 lint 规则的包。使用此包可以鼓励团队中的良好编码实践。

反馈

#

随着网站此部分的不断发展,我们欢迎您的反馈