跳至主要内容

常见的架构概念

在本节中,您将找到一些经过验证的原则,这些原则指导着更广泛的应用程序开发领域中的架构决策,以及有关它们如何具体融入 Flutter 的信息。这是一个关于推荐架构和最佳实践相关的词汇和概念的简要介绍,以便您可以在本指南中更详细地探索它们。

关注点分离

#

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

在 Flutter 中,这同样适用于 UI 层中的 Widget。您应该编写可重用、精简的 Widget,这些 Widget 应尽可能少地包含逻辑。

分层架构

#

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 层中的 Widget。用户交互产生的事件则反向流动,从表示层流经逻辑层到达数据层。

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 层] 由于用户交互(例如单击按钮)而发生事件。Widget 的事件处理程序回调调用逻辑层中类的公开方法。
  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,而不是反过来。数据应该是不可变的和持久的,视图应该包含尽可能少的逻辑。这最大限度地减少了应用程序关闭时数据丢失的可能性,并使您的应用程序更易于测试并更能抵御错误。

可扩展性

#

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

以这种方式使用干净的接口,您可以交换类的具体实现,而无需更改使用该接口的任何代码。

可测试性

#

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

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

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

反馈

#

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