architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTechnology Stack
技术栈
- Flutter for cross-platform development
- Dart as the primary programming language
- bloc for state management
- injectable for dependency injection
- Dart Mappable for immutable data models
- Dio for HTTP networking
- isar for local database
- Firebase for backend services
- Flutter用于跨平台开发
- Dart作为主要编程语言
- bloc用于状态管理
- injectable用于依赖注入
- Dart Mappable用于实现不可变数据模型
- Dio用于HTTP网络请求
- isar用于本地数据库
- Firebase提供后端服务
Clean Architecture
整洁架构
- Domain Purity: The layer must be pure Dart. NO
domainimports.package:flutter - Layer Dependency: . Data layer implements Domain interfaces.
Presentation -> Domain <- Data - Feature-First 2.0: Enforce strict separation of (External/Raw) vs
DataSources(Domain abstraction).Repositories
- 领域层纯净性:层必须为纯Dart代码,禁止导入
domain。package:flutter - 层依赖规则:,数据层实现领域层定义的接口。
表示层 -> 领域层 <- 数据层 - Feature-First 2.0:严格区分与
数据源(DataSources,外部/原始数据)。仓库(Repositories,领域层抽象)
Directory Structure
目录结构
- Organize code according to feature-based Clean Architecture pattern (,
featureA/bloc,featureA/models)featureA/views - Place cross-feature components in the directory
core - Group shared widgets in by type
core/views/widgets
- 按照基于特性的整洁架构模式组织代码(如、
featureA/bloc、featureA/models)featureA/views - 跨特性通用组件放置在目录下
core - 共享Widget按类型归类到目录
core/views/widgets
Three-Layer Data Model Pattern
三层数据模型模式
-
API Layer (ItemApiModel)
- Represents the raw data structure as received from the server
- Contains all fields provided by the API
- Should match the API contract exactly
-
Domain Layer (Item)
- Represents the internal data model
- Contains only the fields necessary for business logic
- Strips out unnecessary API fields
-
UI Layer (ItemUiState)
- Represents the data model optimized for UI rendering
- Contains parsed and formatted data ready for display
- Handles all UI-specific transformations
-
API层(ItemApiModel)
- 表示从服务端获取的原始数据结构
- 包含API返回的所有字段
- 必须与API契约完全一致
-
领域层(Item)
- 表示内部业务数据模型
- 仅包含业务逻辑所需的字段
- 剔除API返回的不必要字段
-
UI层(ItemUiState)
- 表示为UI渲染优化的数据模型
- 包含已解析格式化、可直接展示的数据
- 处理所有UI专属的格式转换逻辑
Data Model Rules
数据模型规则
- Use Dart Mappable for defining immutable UI states
- Each layer should have its own type definition
- The UI layer should use the UI state data models, never directly the domain model or the API model
- The UI state model should be derived from the domain model, not the API model
- The domain model should be derived from the API model, not the UI state model
- 使用Dart Mappable定义不可变UI状态
- 每一层都应有独立的类型定义
- UI层必须使用UI状态数据模型,禁止直接使用领域模型或API模型
- UI状态模型必须从领域模型派生,不能直接从API模型派生
- 领域模型必须从API模型派生,不能从UI状态模型派生
Repository & DataSource Pattern
仓库与数据源模式
- Repositories orchestrate between data sources (return Domain Model)
- Data sources access raw data (return API Model)
- The repository should be the source of truth, and it returns the domain model
- DataSources MUST only contain raw SDK/API calls. No mapping or business logic.
- No direct backend SDK/API calls outside DataSources
- 仓库负责协调多个数据源,返回领域模型
- 数据源负责访问原始数据,返回API模型
- 仓库作为唯一可信数据源,返回领域模型
- 数据源必须仅包含原始SDK/API调用,不能包含映射逻辑或业务逻辑
- 禁止在数据源之外直接调用后端SDK/API
Data Flow
数据流
UI Event → BLoC (emit Loading) → Repository → DataSource (API/SDK)
↓
Response → Repository (map to Domain Entity) → BLoC (emit Success/Error) → UIUI Event → BLoC (emit Loading) → Repository → DataSource (API/SDK)
↓
Response → Repository (map to Domain Entity) → BLoC (emit Success/Error) → UIDart 3 Language Features
Dart 3 语言特性
- Sealed Classes: Use for domain failures to enable exhaustive pattern matching across layers.
sealed class - Records: Use records for lightweight multi-value returns where defining a full class is overkill (e.g., ).
(String name, int age) - If-Case Pattern: Prefer over
if (value case final v?)for null checking with binding.if (value != null) - Class Modifiers: Use ,
final,interface, andbaseclass modifiers to express API intent.sealed
- 密封类(Sealed Classes):使用定义领域异常,实现各层的穷尽模式匹配。
sealed class - 记录(Records):对于不需要定义完整类的轻量级多值返回场景使用记录(例如)。
(String name, int age) - If-Case 模式:空值检查优先使用而非
if (value case final v?),同时完成变量绑定。if (value != null) - 类修饰符:使用、
final、interface、base类修饰符明确表达API设计意图。sealed
Error Handling
错误处理
- Functional Error Handling: Use or
Either<Failure, T>sealed classes. NEVER throw exceptions across layer boundaries.Result<T> - Pattern Matching: Exhaustively handle all sealed class states using Dart 3.x expressions in UI and BLoCs.
switch - Throw errors when needed, and catch them at appropriate boundaries
- Log errors with context
- Present user-friendly error messages in the UI
- Avoid silent failures; always handle or propagate errors
- 函数式错误处理:使用或
Either<Failure, T>密封类,绝对禁止跨层边界抛出异常。Result<T> - 模式匹配:在UI和BLoC中使用Dart 3.x的表达式穷尽处理所有密封类状态。
switch - 必要时抛出错误,并在合适的边界捕获
- 记录错误日志并附带上下文信息
- 在UI中展示用户友好的错误提示
- 避免静默失败,始终处理或向上传播错误
Platform Channels & Native Integration
平台通道与原生集成
- Use for one-off calls to native code (e.g., reading device info, triggering native APIs)
MethodChannel - Use for continuous streams from native to Flutter (e.g., sensor data, connectivity changes)
EventChannel - Place all channel code in a dedicated directory within the relevant feature
platform/ - Define channel names as constants:
static const channel = MethodChannel('com.app.feature/method') - Wrap all channel calls in a DataSource — never call directly from BLoC or UI
MethodChannel - Handle gracefully for platforms that don't implement the channel
MissingPluginException - Use checks to guard platform-specific behavior
defaultTargetPlatform
- 单次调用原生代码使用(例如读取设备信息、调用原生API)
MethodChannel - 原生向Flutter持续发送数据流使用(例如传感器数据、网络连接状态变化)
EventChannel - 所有通道代码放置在对应特性下的专属目录中
platform/ - 将通道名称定义为常量:
static const channel = MethodChannel('com.app.feature/method') - 所有通道调用都要封装在数据源中,禁止从BLoC或UI层直接调用
MethodChannel - 对于未实现对应通道的平台,优雅处理
MissingPluginException - 使用判断来管控平台专属行为
defaultTargetPlatform
FFI (Foreign Function Interface)
FFI(外部函数接口)
- Use for performance-critical native C/C++ code
dart:ffi - Define bindings in a separate class with clear documentation
- Prefer Federated Plugins when sharing native code across multiple packages
- 性能敏感的原生C/C++代码调用使用
dart:ffi - 在独立类中定义绑定并添加清晰的文档说明
- 跨多包共享原生代码时优先使用联邦插件(Federated Plugins)
Platform-Specific Code
平台专属代码
- Use /
Platform.isAndroidfor runtime checks (importPlatform.isIOS)dart:io - For web, use from
kIsWebpackage:flutter/foundation.dart - Prefer adaptive widgets (,
Switch.adaptive) over manual platform checks where possibleSlider.adaptive
- 运行时平台判断使用/
Platform.isAndroid(需导入Platform.isIOS)dart:io - Web端判断使用提供的
package:flutter/foundation.dartkIsWeb - 优先使用自适应Widget(、
Switch.adaptive),而非手动编写平台判断逻辑Slider.adaptive