在本节中,您将找到在更广泛的应用程序开发领域中指导架构决策的经过验证的原则,以及它们如何专门应用于 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的类中,该类是数据层的一部分。对于您应用程序中的每种数据类型,通常有一个存储库类。

此原则还可以应用于应用程序的各层和组件,以及单个类中。例如,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. [逻辑层] 逻辑类调用存储库公开的方法,这些方法知道如何修改数据。
  3. [数据层] 存储库更新数据(如果需要),然后将新数据提供给逻辑类。
  4. [逻辑层] 逻辑类保存其新状态,并将其发送到 UI。
  5. [UI 层] UI 显示视图模型的新状态。

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

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

#

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

UI is a function of state.

至关重要的是,您的数据应驱动 UI,而不是反之。数据应该是不可变的和持久的,而视图应包含尽可能少的逻辑。这最大限度地减少了应用程序关闭时数据丢失的可能性,并使您的应用程序更易于测试,并且更能抵抗错误。

可扩展性

#

架构的每个部分都应该有一组定义明确的输入和输出。例如,逻辑层中的视图模型应该只接受数据源作为输入,例如存储库,并且只公开格式化后的命令和数据供视图使用。

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

可测试性

#

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

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

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

反馈

#

由于本网站的部分内容正在不断更新,我们欢迎您的反馈