在本节中,你将找到指导应用程序开发领域架构决策的行之有效的原则,以及它们如何具体适用于 Flutter 的信息。这是对推荐架构和最佳实践相关词汇和概念的简要介绍,以便你可以在本指南中更详细地探索它们。

关注点分离

#

关注点分离是应用程序开发中的一个核心原则,通过将应用程序的功能划分为独立、自包含的单元,从而提高模块化和可维护性。从高层次上看,这意味着将你的 UI 逻辑与业务逻辑分开。这通常被称为分层架构。在每个层中,你应该根据特性或功能进一步分离你的应用程序。例如,你应用程序的认证逻辑应该与搜索逻辑位于不同的类中。

在 Flutter 中,这也适用于 UI 层中的小部件。你应该编写可重用、精简的小部件,其中包含尽可能少的逻辑。

分层架构

#

Flutter 应用程序应该分层编写。分层架构是一种软件设计模式,它将应用程序组织成不同的层,每层都有特定的角色和职责。通常,应用程序会根据复杂性分为 2 到 3 层。

The three common layers of app architecture, the UI layer, logic layer, and data layer.
  • UI 层 - 向用户显示由业务逻辑层公开的数据,并处理用户交互。这通常也被称为“展示层”。
  • 逻辑层 - 实现核心业务逻辑,并促进数据层和 UI 层之间的交互。通常称为“领域层”。逻辑层是可选的,只有当你的应用程序包含在客户端发生的复杂业务逻辑时才需要实现。许多应用程序只关注向用户呈现数据并允许用户更改该数据(俗称 CRUD 应用程序)。这些应用程序可能不需要这个可选层。
  • 数据层 - 管理与数据源(例如数据库或平台插件)的交互。向业务逻辑层公开数据和方法。

之所以称之为“层”,是因为每层只能与其直接下方或上方的层进行通信。UI 层不应该知道数据层的存在,反之亦然。

单一数据源

#

你的应用程序中的每种数据类型都应该有一个单一数据源(SSOT)。单一数据源负责表示本地或远程状态。如果数据可以在应用程序中修改,那么 SSOT 类应该是唯一能够执行此操作的类。

这可以显著减少应用程序中的错误数量,并能简化代码,因为你将只拥有相同数据的一个副本。

通常,你的应用程序中任何给定数据类型的单一数据源都保存在一个名为 Repository 的类中,该类是数据层的一部分。你的应用程序中每种数据类型通常有一个 Repository 类。

此原则可应用于应用程序的各个层和组件,以及单个类内部。例如,一个 Dart 类可以使用 getter 从 SSOT 字段派生值(而不是拥有多个需要独立更新的字段),或者使用 记录 列表来分组相关值(而不是可能出现索引不同步的并行列表)。

单向数据流

#

单向数据流(UDF)是指一种设计模式,有助于将状态与显示该状态的 UI 解耦。最简单地说,状态从数据层流经逻辑层,最终到达 UI 层中的小部件。用户交互产生的事件则沿相反方向流动,从展示层回流到逻辑层并到达数据层。

The three common layers of app architecture, the UI layer, logic layer, and data layer, and the flow of state from the data layer to the UI layer.

在 UDF 中,从用户交互到重新渲染 UI 的更新循环如下所示:

  1. 【UI 层】由于用户交互(例如按钮点击)而发生事件。小部件的事件处理程序回调会调用逻辑层中某个类公开的方法。
  2. 【逻辑层】逻辑类调用 Repository 公开的、知道如何修改数据的方法。
  3. 【数据层】Repository 更新数据(如有必要),然后将新数据提供给逻辑类。
  4. 【逻辑层】逻辑类保存其新状态,并将其发送到 UI。
  5. 【UI 层】UI 显示视图模型的新状态。

新数据也可以从数据层开始。例如,Repository 可能会轮询 HTTP 服务器以获取新数据。在这种情况下,数据流只完成了后半段旅程。最重要的思想是,数据更改始终发生在单一数据源(SSOT)中,即数据层。这使得你的代码更易于理解,更不容易出错,并能防止创建格式错误或意外的数据。

UI 是 (不可变) 状态的函数

#

Flutter 是声明式的,这意味着它构建 UI 以反映应用程序的当前状态。当状态发生变化时,你的应用程序应该触发依赖于该状态的 UI 重建。在 Flutter 中,你经常会听到这种描述:“UI 是状态的函数”。

UI is a function of state.

至关重要的是,你的数据应该驱动 UI,而不是反过来。数据应该是不可变和持久的,并且视图应包含尽可能少的逻辑。这能最大限度地减少应用程序关闭时数据丢失的可能性,并使你的应用程序更具可测试性和更强的抗 bug 能力。

可扩展性

#

每部分架构都应该有明确定义的输入和输出列表。例如,逻辑层中的视图模型应该只接收数据源(如 Repository)作为输入,并且只公开命令和为视图格式化的数据。

以这种方式使用清晰的接口,可以让你在不更改任何使用该接口的代码的情况下,替换类的具体实现。

可测试性

#

使软件可扩展的原则也使软件更容易测试。例如,你可以通过模拟 Repository 来测试视图模型的自包含逻辑。视图模型测试不需要你模拟应用程序的其他部分,并且你可以将 UI 逻辑与 Flutter 小部件本身分开测试。

你的应用程序也将更加灵活。添加新逻辑和新 UI 将是直接且低风险的。例如,添加新的视图模型不会破坏数据层或业务逻辑层中的任何逻辑。

下一节将解释应用程序架构中任何给定组件的输入和输出概念。

反馈

#

由于本网站的此部分正在不断完善中,我们欢迎你的反馈