Skip to content

项目架构

良好的项目架构是可维护、可扩展代码的基础。本章介绍 Flutter 项目中常用的目录组织方式和架构模式。

推荐目录结构

对于中小型项目,推荐以下目录组织方式:

lib/
├── main.dart                # 应用入口,只做初始化和启动
├── app.dart                 # 根 Widget(MaterialApp/CupertinoApp)
├── config/                  # 配置常量
│   ├── theme.dart           #   主题配置
│   ├── routes.dart          #   路由配置
│   └── constants.dart       #   全局常量(API 地址、缓存 key 等)
├── pages/                   # 页面(每个页面一个文件夹)
│   ├── home/
│   │   └── home_page.dart
│   ├── login/
│   │   └── login_page.dart
│   └── profile/
│       └── profile_page.dart
├── widgets/                 # 可复用组件
│   ├── loading_indicator.dart
│   ├── empty_state.dart
│   └── custom_button.dart
├── models/                  # 数据模型
│   ├── user.dart
│   └── product.dart
├── services/                # 服务层(网络请求、本地存储等)
│   ├── api_service.dart
│   └── storage_service.dart
└── utils/                   # 工具函数
    ├── date_formatter.dart
    └── validators.dart

核心原则

  • 按功能分层:页面、组件、模型、服务各归其位
  • 页面独立:每个页面一个文件夹,页面专属组件放在同目录下
  • 共享组件提取:被多个页面使用的组件放到 widgets/
  • 入口简洁main.dart 只负责启动,不超过 20 行

大型项目目录结构

项目变大后,推荐按 功能模块 组织:

lib/
├── main.dart
├── app.dart
├── core/                    # 核心公共层
│   ├── theme/
│   ├── routes/
│   ├── network/             #   dio 封装、拦截器
│   └── storage/             #   本地存储封装
├── features/                # 按功能模块组织
│   ├── auth/                #   登录/注册模块
│   │   ├── auth_page.dart
│   │   ├── auth_controller.dart  # 状态逻辑
│   │   ├── widgets/              # 模块专属组件
│   │   └── models/
│   ├── home/
│   │   ├── home_page.dart
│   │   └── widgets/
│   └── profile/
│       ├── profile_page.dart
│       └── widgets/
└── shared/                  # 跨模块共享
    ├── widgets/
    ├── models/
    └── utils/

何时切换到功能模块结构?

当项目超过 10 个页面 或有 3 人以上 协作时,建议切换到功能模块结构。小项目用分层结构即可,过度设计反而增加复杂度。

架构模式选择

最简方案:StatefulWidget

适合个人小项目、Demo、学习阶段:

dart
class CounterPage extends StatefulWidget {
  const CounterPage({super.key});

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _count = 0;

  void _increment() => setState(() => _count++);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: Text('$_count')),
      floatingActionButton: FloatingActionButton(
        onPressed: _increment,
        child: const Icon(Icons.add),
      ),
    );
  }
}

优点: 零依赖,上手最快
缺点: 逻辑和 UI 耦合,难以测试和复用

推荐方案:Provider + 分层

适合大多数正式项目,是 Flutter 官方推荐的状态管理方案:

dart
// 1. 控制器(逻辑层)
class CounterController extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

// 2. 顶层注入
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CounterController(),
      child: const MyApp(),
    ),
  );
}

// 3. 页面(展示层)
class CounterPage extends StatelessWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context) {
    final count = context.watch<CounterController>().count;

    return Scaffold(
      body: Center(child: Text('$count')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterController>().increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

优点: 逻辑与 UI 分离,可测试,社区成熟
缺点: 需要理解 Provider 机制

架构模式对比

模式适用场景复杂度可测试性
StatefulWidgetDemo / 学习★☆☆★☆☆
Provider + 分层中小型项目★★☆★★★
Riverpod + 功能模块大型项目★★★★★★

建议

初学者先掌握 StatefulWidget,理解状态管理的基本概念后,再学习 Provider。不要一开始就追求复杂架构。

常见错误

1. 把所有代码写在 main.dart

dart
// ❌ 错误:所有代码堆在一个文件
void main() => runApp(const MyApp());

class MyApp extends StatelessWidget { ... }
class HomePage extends StatefulWidget { ... }
class _HomePageState extends State<HomePage> { ... }
class SettingsPage extends StatelessWidget { ... }
class UserModel { ... }
class ApiService { ... }
dart
// ✅ 正确:按职责拆分到不同文件
// main.dart - 只做启动
// pages/home/home_page.dart
// pages/settings/settings_page.dart
// models/user.dart
// services/api_service.dart

2. 过度封装

dart
// ❌ 过度封装:只有一个地方用,没必要单独建文件
widgets/buttons/primary_action_button/
  ├── primary_action_button.dart
  └── primary_action_button_style.dart
dart
// ✅ 合理封装:至少 2-3 处复用时才提取
widgets/
  └── custom_button.dart    # 简洁明了

3. 忽略分析规则

yaml
# analysis_options.yaml - 推荐配置
include: package:flutter_lints/flutter.yaml

linter:
  rules:
    prefer_const_constructors: true
    prefer_const_declarations: true
    avoid_print: true
    prefer_single_quotes: true

运行 flutter analyze 检查代码质量,在 CI/CD 中加入此步骤。

下一步

基于 Flutter 官方文档整理