常见的架构概念
在本节中,您将找到指导大型应用开发架构决策的久经考验的原则,以及它们如何融入 Flutter 的具体信息。这是一个关于推荐架构和最佳实践相关词汇和概念的简要介绍,以便您可以在本指南中更详细地探索它们。
关注点分离
#关注点分离 是应用开发中的核心原则,它通过将应用程序的功能划分为不同的、独立的单元来促进模块化和可维护性。从高层次来看,这意味着将您的 UI 逻辑与您的业务逻辑分开。这通常被称为 分层 架构。在每一层中,您应该通过功能进一步分离您的应用程序。例如,您的应用程序的身份验证逻辑应该与搜索逻辑位于不同的类中。
在 Flutter 中,这也适用于 UI 层中的小部件。您应该编写可重用、精简的小部件,这些小部件包含尽可能少的逻辑。
分层架构
#Flutter 应用程序应该分层编写。分层架构是一种软件设计模式,它将应用程序组织成不同的层,每一层都有特定的角色和职责。通常,应用程序根据复杂性分为 2 到 3 层。
![应用程序架构的三个常见层:UI 层、逻辑层和数据层。](/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-icons.png)
- UI 层 - 显示业务逻辑层公开给用户的数据,并处理用户交互。这通常也称为“表示层”。
- 逻辑层 - 实现核心业务逻辑,并促进数据层和 UI 层之间的交互。通常称为“领域层”。逻辑层是可选的,只有当您的应用程序具有在客户端发生的复杂业务逻辑时才需要实现。许多应用程序只关注向用户呈现数据并允许用户更改该数据(俗称 CRUD 应用程序)。这些应用程序可能不需要此可选层。
- 数据层 - 管理与数据源(例如数据库或平台插件)的交互。向业务逻辑层公开数据和方法。
这些被称为“层”,因为每一层只能与其直接下层或上层通信。UI 层不应该知道数据层的存在,反之亦然。
单一事实来源
#应用程序中的每种数据类型都应该具有单一事实来源 (SSOT)。事实来源负责表示本地或远程状态。如果数据可以在应用程序中修改,则 SSOT 类应该是唯一可以执行此操作的类。
这可以大大减少应用程序中的错误数量,并且可以简化代码,因为您将只有一个相同数据的副本。
通常,应用程序中任何给定类型数据的真相来源都保存在名为 存储库 的类中,该类是数据层的一部分。您的应用程序中每种类型的数据通常都有一个存储库类。
此原则也可以应用于应用程序中的各层和组件以及各个类中。例如,Dart 类可以使用getter 从 SSOT 字段派生值(而不是拥有需要独立更新的多个字段)或记录 列表来分组相关值(而不是索引可能不同步的并行列表)。
单向数据流
#单向数据流 (UDF) 指的是一种设计模式,它有助于将状态与显示该状态的 UI 解耦。简而言之,状态从数据层流经逻辑层,最终到达 UI 层中的小部件。来自用户交互的事件则反向流动,从表示层流经逻辑层到数据层。
![应用程序架构的三个常见层:UI 层、逻辑层和数据层,以及状态从数据层到 UI 层的流程。](/assets/images/docs/app-architecture/common-architecture-concepts/horizontal-layers-with-UDF.png)
在 UDF 中,来自用户交互到重新渲染 UI 的更新循环如下所示:
- [UI 层] 由于用户交互(例如单击按钮)而发生事件。小部件的事件处理程序回调调用逻辑层中类的公开方法。
- [逻辑层] 逻辑类调用存储库公开的方法,这些方法知道如何改变数据。
- [数据层] 存储库更新数据(如有必要),然后将新数据提供给逻辑类。
- [逻辑层] 逻辑类保存其新状态,然后将其发送到 UI。
- [UI 层] UI 显示视图模型的新状态。
新数据也可以从数据层开始。例如,存储库可能会轮询 HTTP 服务器以获取新数据。在这种情况下,数据流只完成了旅程的后半部分。最重要的思想是数据更改总是发生在SSOT(即数据层)中。这使得您的代码更容易理解,不易出错,并防止创建格式错误或意外的数据。
UI 是(不可变)状态的函数
#Flutter 是声明式的,这意味着它构建其 UI 以反映应用程序的当前状态。当状态更改时,您的应用程序应触发依赖于该状态的 UI 的重建。在 Flutter 中,您经常会听到这被称为“UI 是状态的函数”。
![UI 是状态的函数。](/assets/images/docs/app-architecture/common-architecture-concepts/ui-f-state.png)
至关重要的是,您的数据驱动您的 UI,而不是相反。数据应该是不可变的和持久的,视图应该包含尽可能少的逻辑。这最大限度地减少了应用程序关闭时数据丢失的可能性,并使您的应用程序更易于测试并且更能抵抗错误。
可扩展性
#每个架构部分都应该有一个定义明确的输入和输出列表。例如,逻辑层中的视图模型应该只将数据源作为输入(例如存储库),并且应该只公开为视图格式化的命令和数据。
以这种方式使用清晰的接口允许您交换类的具体实现,而无需更改使用该接口的任何代码。
可测试性
#使软件可扩展的原则也使软件更易于测试。例如,您可以通过模拟存储库来测试视图模型的自包含逻辑。视图模型测试不需要您模拟应用程序的其他部分,您可以单独测试 UI 逻辑,而无需使用 Flutter 小部件本身。
您的应用程序也将更加灵活。添加新的逻辑和新的 UI 将变得简单且风险较低。例如,添加新的视图模型不会破坏数据层或业务逻辑层的任何逻辑。
下一节将解释应用程序架构中任何给定组件的输入和输出的概念。
反馈
#由于本网站的这一部分正在不断发展,我们欢迎您的反馈!
除非另有说明,否则本网站上的文档反映的是 Flutter 的最新稳定版本。页面最后更新于 2025-01-30。 查看源代码 或 报告问题。