• 作者:老汪软件技巧
  • 发表时间:2024-12-13 07:05
  • 浏览量:66

构建 Flutter 应用的架构指南

架构是构建可维护、具有弹性和可扩展 Flutter 应用的重要组成部分。在本指南中,您将学习构建 Flutter 应用的架构原则和最佳实践。

“架构”这个词难以定义。它是一个广泛的术语,根据上下文可以涉及多个主题。在本指南中,“架构”指的是如何组织、设计和构建您的 Flutter 应用,以便随着项目需求和团队规模的增长而扩展。

您将学到什么有意架构的好处

良好的应用架构为工程团队和最终用户提供了许多好处。

如何使用本指南

本指南旨在帮助构建可扩展的 Flutter 应用,特别适合由多个开发人员共同参与同一代码库并构建功能丰富应用的团队。如果您正在开发一个团队和代码库都在增长的 Flutter 应用,本指南非常适合您。

除了通用的架构建议,本指南还提供了具体的最佳实践示例和具体推荐。一些库可以根据需要替换,而对于具有独特复杂性的超大型团队,其中某些部分可能不适用。但无论如何,这些理念是可靠的。这是构建 Flutter 应用的推荐方式。

在本指南的第一部分,您将从宏观层面了解常见的架构原则。在第二部分,本指南将具体阐述构建 Flutter 应用架构的推荐做法。最后,在指南结尾处,您将找到一系列设计模式和示例代码,展示这些建议的实际应用。

常见架构概念

在本节中,您将学习应用开发领域中广泛应用的架构原则,以及它们在 Flutter 中的具体应用。这是一份关于推荐架构和最佳实践的词汇和概念的入门介绍,后续内容将进一步详细展开这些概念。

职责分离

职责分离是应用开发中的核心原则之一,通过将应用的功能划分为独立的、自包含的模块,促进模块化和可维护性。从高层次来看,这意味着将用户界面逻辑与业务逻辑分离。这通常被描述为分层架构。在每一层中,还需要按照功能或特性进一步细化应用。例如,认证逻辑应与搜索逻辑分属于不同的类。

在 Flutter 中,这一原则同样适用于 UI 层的组件。您应该编写可重用且逻辑简单的组件,使其包含尽可能少的逻辑。

分层架构

Flutter 应用应采用分层结构。分层架构是一种将应用分为不同层级的软件设计模式,每层都具有特定的角色和职责。根据应用的复杂程度,通常划分为 2 到 3 层。

常见的三层架构包括:

这些层被称为“层”,因为每层只能与直接上下的层通信。UI 层不应直接知道数据层的存在,反之亦然。

单一数据源原则

每种数据类型在应用中都应有单一数据源(SSOT) ,负责表示本地或远程状态。如果数据在应用中可被修改,则 SSOT 类应是唯一能够进行修改的类。

此原则可显著减少应用中的错误,并简化代码,因为您只需管理数据的一个副本。

通常,应用中的数据由称为 Repository(仓库) 的类管理,该类位于数据层中。通常每种数据类型对应一个仓库类。

在应用的层级和组件中,以及单个类内都可以应用此原则。例如,一个 Dart 类可以通过 getter 方法从单一数据源字段派生值,而不是通过多个字段独立更新数据。

单向数据流

单向数据流(UDF) 是一种设计模式,帮助将状态与显示状态的 UI 分离。简单来说,状态从数据层流向逻辑层,最终到达 UI 层的组件,而用户交互事件则反方向流动。

状态更新的过程如下:

UI 层:用户交互触发事件,例如点击按钮。组件的事件处理回调调用逻辑层中的方法。逻辑层:逻辑类调用仓库提供的方法来修改数据。数据层:仓库更新数据(如果需要),并将新数据提供给逻辑类。逻辑层:逻辑类保存新状态并发送给 UI。UI 层:UI 根据新状态重新渲染。

状态变化始终发生在单一数据源(即数据层),这使代码更易理解、减少错误,并避免生成格式错误或意外的数据。

UI 是状态的函数

Flutter 是声明式的,意味着它的 UI 反映应用的当前状态。当状态改变时,应用会触发依赖于该状态的 UI 的重建。这通常被描述为“UI 是状态的函数”。

关键是数据应驱动 UI,而不是反过来。数据应保持不可变性和持久性,视图应尽可能少包含逻辑。这样可以最大程度减少应用关闭时数据丢失的可能性,并使应用更易测试且更能抵御错误。

可扩展性

每个架构组件都应有明确的输入和输出。例如,逻辑层的视图模型应只接受数据源(如仓库)作为输入,并仅输出格式化为视图所需的命令和数据。

通过这种方式使用干净的接口,可以在不更改消费接口代码的情况下替换具体的类实现。

可测试性

支持扩展的软件通常也更易于测试。例如,您可以通过模拟一个仓库来测试视图模型的独立逻辑。视图模型的测试无需模拟应用的其他部分,您可以将 UI 逻辑的测试与 Flutter 组件本身分离。

应用也会更加灵活。例如,添加新的逻辑或新的 UI 会是低风险且直接的过程,因为新增的视图模型不会破坏数据或业务逻辑层的其他部分。

下一节将详细解释架构中各组件的输入和输出。

应用架构指南

以下内容展示了如何使用最佳实践构建应用程序。本指南中的推荐内容适用于大多数应用,能使其更易扩展、测试和维护。然而,这些仅是指导原则,而非硬性规定,您应根据自身需求进行调整。

本节提供了 Flutter 应用架构的高层概述,解释了应用的分层结构以及每一层中涉及的类。接下来的部分将通过具体的代码示例,详细讲解如何在 Flutter 应用中实现这些推荐方法。

项目结构概述

职责分离 是设计 Flutter 应用时最重要的原则。您的 Flutter 应用应分为两个主要层次:UI 层 和 数据层。

每一层进一步划分为具有明确职责、清晰接口、边界和依赖的组件。本指南建议您将应用划分为以下组件:

MVVM 设计模式

如果您熟悉 Model-View-ViewModel (MVVM) 设计模式,这将非常熟悉。MVVM 是一种设计模式,将应用的某个功能划分为三个部分:模型(Model) 、视图模型(ViewModel) 和 视图(View) 。

MVVM 设计模式的核心概念

每个应用功能包含以下对象:

一个视图,用于描述 UI。一个视图模型,用于处理逻辑。一个或多个仓库,作为应用数据的单一数据源。零个或多个服务,用于与外部 API(如客户端服务器或平台插件)交互。

在复杂应用中,可能会增加一个位于 UI 层和数据层之间的逻辑层(通常称为 领域层),用于进一步抽象复杂业务逻辑。

UI 层

UI 层 负责与用户交互,展示应用数据,并接收用户输入(例如点击事件、表单输入)。

UI 层的两个架构组件

视图(Views)

定义如何向用户呈现数据。由多个 小部件(widgets) 组成。响应用户交互,将事件传递给视图模型。

视图模型(View Models)

将数据层的数据转换为适合 UI 显示的格式。维护视图所需的状态,确保在配置变化(如屏幕旋转)时不会丢失数据。暴露回调函数(称为命令),供视图处理用户交互。

视图和视图模型应保持 1:1 的关系。

数据层

数据层 处理业务数据和逻辑,主要由两部分组成:仓库 和 服务。

仓库(Repositories)

负责获取数据(通过服务)并转换为领域模型(适合视图模型使用的格式)。管理业务逻辑,例如缓存、错误处理、数据轮询等。

服务(Services)

包装 API 端点,提供异步响应对象(如 Future 和 Stream)。不持有状态,仅用于隔离数据加载。

仓库与服务之间,以及仓库与视图模型之间,都存在多对多关系。

可选:领域层

在应用复杂度增加时,您可以引入 领域层(Domain Layer) ,将复杂业务逻辑从视图模型中抽象出来。

flutterui构建工具__flutter架构设计

领域层的主要作用领域层的优劣分析数据访问和领域层的使用规则

当引入领域层时,您需要决定:

最佳方法是仅在需要时添加领域层。如果发现大多数视图模型都在通过领域层访问数据,可以随时重构代码以全面使用领域层。

通过上述架构设计,您可以构建一个具有高可扩展性、易维护性和良好测试性的 Flutter 应用。在本指南后续章节中,您将看到这些设计原则如何在代码中具体实现。

架构建议范围建议优先级描述

职责分离

清晰定义数据层与 UI 层

强烈推荐

职责分离是最重要的架构原则。数据层负责提供应用数据,并包含大部分业务逻辑;UI 层负责展示数据和监听用户事件。UI 层应进一步划分为单独的逻辑类和组件类。

职责分离

在数据层中使用仓库模式

强烈推荐

仓库模式为数据访问逻辑和其他应用逻辑创建抽象层。您应在数据层中创建 Repository 和 Service 类,用于隔离数据存储机制(如数据库、API、文件系统等)。

职责分离

在 UI 层使用视图模型和视图(MVVM)

强烈推荐

此分离方式使代码更少出错,因为组件保持“无状态”。

职责分离

使用 ChangeNotifier 和 Listenables 处理组件更新

条件推荐

ChangeNotifier 是 Flutter SDK 的一部分,提供了方便的方式让组件观察视图模型的变化。其他状态管理选项也可根据偏好选择。

职责分离

不要在组件中放置逻辑

强烈推荐

所有逻辑应封装在视图模型的方法中。组件中的逻辑仅限以下内容:简单的 if 语句,用于根据视图模型中的标志显示或隐藏组件;与组件关联的动画逻辑;基于设备信息(如屏幕大小或方向)的布局逻辑;简单的路由逻辑。

职责分离

使用领域层

条件推荐

领域层适用于需要简化视图模型逻辑或减少重复逻辑的场景。对于大型应用,领域层有用,但对小型应用可能增加不必要的复杂性。

处理数据

使用单向数据流

强烈推荐

数据更新应仅从数据层流向 UI 层,用户交互事件从 UI 层传递到数据层处理。

处理数据

使用命令处理用户交互事件

推荐

命令模式可避免渲染错误并标准化 UI 层向数据层发送事件的方式。

处理数据

使用不可变数据模型

强烈推荐

不可变数据可确保数据仅在模型中更新,减少错误。

处理数据

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

推荐

这些工具可生成常见方法(如 JSON 序列化/反序列化、深度相等检查和复制方法),但可能会增加构建时间。

处理数据

创建单独的 API 模型和领域模型

条件推荐

虽然增加了代码冗长,但有助于防止视图模型和用例中的复杂性,适用于大型应用。

App 架构

使用依赖注入

强烈推荐

依赖注入可避免全局对象的使用,降低代码出错概率。推荐使用 provider 包来管理依赖注入。

App 架构

使用 go_router 进行导航

推荐

go_router 适合 90% 的 Flutter 应用。对于特定用例,可使用 Flutter Navigator API 或其他社区包。

App 架构

使用标准命名约定

推荐

命名应明确反映架构组件的作用。例如:HomeViewModel、HomeScreen、UserRepository、ClientApiService。

App 架构

使用抽象仓库类

强烈推荐

抽象仓库类允许为不同环境(如开发、测试)创建不同实现。

App 架构

分别测试架构组件并联合测试

强烈推荐

为每个服务、仓库和视图模型类编写单元测试;为视图编写组件测试,重点测试路由和依赖注入。

App 架构

为测试创建假对象(Fake)

强烈推荐

假对象关注输入和输出,而非方法的内部实现。这促使代码模块化、轻量化,并拥有明确的输入和输出。

资源推荐

Compass App


上一条查看详情 +java如何解析和生成yaml文件?
下一条 查看详情 +没有了
Top