Flutter 架构演进实战:从 MVC 到 Clean Architecture + Modularization 的大型项目重构指南

引言:当你的 Flutter 项目超过 10 万行代码

初期,一个简单的 main.dart + 几个页面就能满足需求。但随着业务增长,代码逐渐演变为:

  • 所有逻辑塞进 StatefulWidget;
  • 网络请求、状态管理、UI 混杂在一起;
  • 修改一处,多处意外崩溃;
  • 新成员入职两周仍不敢提交代码;
  • 构建时间超过 5 分钟。

这正是 架构缺失 的典型症状。许多团队误以为"Flutter 天生组件化",却忽略了分层、解耦、可测试性才是大型项目的生命线。

本文将带你完成一次 真实项目的架构演进 :从混乱的 MVC 式代码,逐步重构为 Clean Architecture + Modularization + Feature-Sliced Design 的现代化结构。我们将覆盖 目录组织、依赖注入、状态管理、模块边界、CI/CD 优化 等核心议题,并提供可直接复用的模板。

目标读者:负责 Flutter 项目架构、技术选型或大型应用维护的工程师与技术负责人。


一、为什么需要 Clean Architecture?

1.1 核心原则:关注点分离(SoC)

Clean Architecture 由 Robert C. Martin 提出,核心思想是:

  • 内层(Entities, Use Cases)不依赖外层(UI, Frameworks)
  • 依赖方向永远指向内层
  • 业务逻辑独立于框架、数据库、UI

1.2 Flutter 中的四层模型

层级 职责 技术栈
Presentation UI、用户交互、路由 Flutter Widgets, Riverpod, GoRouter
Domain 业务逻辑、实体、Use Case Pure Dart, Entities, Repositories(接口)
Data 数据源实现(网络、本地) Dio, Hive, Shared Preferences
Common 工具、扩展、常量 utils/, extensions/, constants/

关键 :Domain 层 零依赖 Flutter SDK,可独立测试与复用。


二、重构第一步:目录结构标准化

2.1 反面教材:按类型组织(Type-Based)

cs 复制代码
1lib/
2├── models/
3├── services/
4├── widgets/
5├── screens/
6└── main.dart

❌ 问题:修改一个功能需横跨多个目录,认知负荷高。

2.2 推荐方案:按特性组织(Feature-Sliced)

cs 复制代码
1lib/
2├── core/                  # 跨特性共享(DI、网络、主题)
3│   ├── di/
4│   ├── network/
5│   └── theme/
6├── features/
7│   ├── auth/              # 登录/注册
8│   │   ├── data/          # Auth 数据源
9│   │   ├── domain/        # Auth 业务逻辑
10│   │   └── presentation/  # 登录页面、状态
11│   └── profile/           # 个人资料
12└── main.dart

优势

  • 功能内聚,修改集中;
  • 新成员快速定位代码;
  • 支持模块懒加载。

三、依赖注入:解耦的核心引擎

3.1 为什么不用 GetIt?

虽然 get_it 简单,但在大型项目中存在:

  • 隐式依赖,难以追踪;
  • 无法按需初始化;
  • 测试时需手动重置。

3.2 推荐:Riverpod + AsyncNotifier

Dart 复制代码
1// features/auth/domain/use_cases/sign_in_use_case.dart
2class SignInUseCase {
3  final AuthRepository repository;
4  SignInUseCase(this.repository);
5
6  Future<User> execute(String email, String password) async {
7    return await repository.signIn(email, password);
8  }
9}
10
11// features/auth/data/repositories/auth_repository_impl.dart
12final authRepositoryProvider = Provider<AuthRepository>((ref) {
13  final dio = ref.watch(dioProvider);
14  return AuthRepositoryImpl(AuthApiClient(dio));
15});
16
17// features/auth/domain/use_cases/sign_in_use_case_provider.dart
18final signInUseCaseProvider = Provider<SignInUseCase>((ref) {
19  final repo = ref.watch(authRepositoryProvider);
20  return SignInUseCase(repo);
21});

优势

  • 依赖显式声明;
  • 自动生命周期管理;
  • 测试时可轻松 Override。

四、状态管理:从 setState 到 AsyncNotifier

4.1 反模式:巨型 StatefulWidget

Dart 复制代码
1class ProfilePage extends StatefulWidget {
2  @override
3  _ProfilePageState createState() => _ProfilePageState();
4}
5
6class _ProfilePageState extends State<ProfilePage> {
7  User? user;
8  bool loading = false;
9
10  void loadUser() async {
11    setState(() => loading = true);
12    final user = await api.getUser(); // 直接调用 API!
13    setState(() {
14      this.user = user;
15      loading = false;
16    });
17  }
18}

❌ 问题:逻辑与 UI 耦合,无法复用,难以测试。

4.2 正确姿势:AsyncNotifier + Use Case

Dart 复制代码
1// features/profile/presentation/notifiers/profile_notifier.dart
2@riverpod
3class ProfileNotifier extends _$ProfileNotifier {
4  @override
5  Future<User?> build() async => null;
6
7  Future<void> loadUser() async {
8    final useCase = ref.read(getUserUseCaseProvider);
9    state = const AsyncLoading();
10    state = await AsyncValue.guard(() => useCase.execute());
11  }
12}
13
14// UI 层
15class ProfilePage extends ConsumerWidget {
16  @override
17  Widget build(BuildContext context, WidgetRef ref) {
18    final userAsync = ref.watch(profileNotifierProvider);
19    return userAsync.when(
20      loading: () => CircularProgressIndicator(),
21      error: (err, _) => Text('Error'),
22      data: (user) => user != null ? UserProfile(user) : LoginButton(),
23    );
24  }
25}

效果

  • 业务逻辑移至 Use Case;
  • 状态可预测、可测试;
  • UI 仅负责渲染。

五、模块化(Modularization):拆分巨型 App

5.1 为什么需要模块化?

  • 编译速度慢(全量编译);
  • 团队并行开发冲突多;
  • 无法按需加载功能。

5.2 使用 flutter_modular 实现

(1)定义模块
Dart 复制代码
1// features/auth/auth_module.dart
2class AuthModule extends Module {
3  @override
4  List<Bind> get binds => [
5        Bind.singleton((i) => AuthRepositoryImpl(i())),
6        Bind.singleton((i) => SignInUseCase(i())),
7      ];
8
9  @override
10  List<ModularRoute> get routes => [
11        ChildRoute('/', child: (_, __) => const LoginPage()),
12        ChildRoute('/register', child: (_, __) => const RegisterPage()),
13      ];
14}
(2)主应用集成
Dart 复制代码
1// main.dart
2void main() {
3  runApp(ModularApp(
4    module: AppModule(),
5    child: const MyApp(),
6  ));
7}
8
9class MyApp extends StatelessWidget {
10  @override
11  Widget build(BuildContext context) {
12    return MaterialApp.router(
13      routeInformationParser: Modular.routeInformationParser,
14      routerDelegate: Modular.routerDelegate,
15    );
16  }
17}

优势

  • 模块自治(路由、依赖、生命周期);
  • 支持动态加载(未来);
  • 团队按模块分工。

六、测试策略:分层保障质量

层级 测试内容 工具
Domain Use Case 逻辑、Entity 方法 test
Data Repository 实现、API Client mocktail, http_mock_adapter
Presentation Widget 渲染、用户交互 flutter_test
Integration 跨模块流程 integration_test

覆盖率目标:Domain ≥ 90%,Data ≥ 80%,Presentation ≥ 70%。


七、CI/CD 优化:加速大型项目构建

7.1 问题:全量构建太慢

  • 每次 PR 都需编译整个 App;
  • 浪费 CI 资源。

7.2 解决方案:按模块缓存

cs 复制代码
1# .github/workflows/test.yml
2- name: Cache modules
3  uses: actions/cache@v4
4  with:
5    path: |
6      **/build/
7      **/.dart_tool/
8    key: ${{ runner.os }}-modules-${{ hashFiles('**/pubspec.lock') }}

7.3 增量测试

bash 复制代码
1# 仅测试变更模块
2changed_files=$(git diff --name-only HEAD~1)
3if echo "$changed_files" | grep -q "features/auth/"; then
4  flutter test test/features/auth/
5fi

八、演进路线图:分阶段重构

阶段 目标 周期
1. 拆分目录 按特性组织代码 1 周
2. 提取 Domain 将业务逻辑移出 UI 2 周
3. 引入 DI 替换硬编码依赖 1 周
4. 模块化 拆分为独立模块 3 周
5. 自动化 CI + 覆盖率门禁 持续

原则小步快跑,持续交付,不追求一步到位


结语:架构不是设计出来的,而是演进出来的

没有银弹架构,只有适合当前团队与业务的结构。本文提供的 Clean + Modular 方案,已在多个百万级用户 App 中验证有效。记住:好的架构让正确的事容易做,错误的事难以发生

行动清单

  1. 本周内将一个功能迁移到 feature 目录;
  2. 为核心 Use Case 编写单元测试;
  3. 在团队内推行目录规范;
  4. 监控构建时间,设定优化目标。

唯有持续演进,才能让 Flutter 项目在规模膨胀中依然保持敏捷与健壮。

欢迎大家加入[开源鸿蒙跨平台开发者社区](https://openharmonycrossplatform.csdn.net),一起共建开源鸿蒙跨平台生态。

相关推荐
西西学代码7 小时前
Flutter---Notification(3)--就寝提醒
flutter
结局无敌7 小时前
Flutter跨平台开发:从原生交互到全端适配的实战拆解
flutter·交互
山屿落星辰7 小时前
Flutter 状态管理终极指南(一):从 setState 到 Riverpod 2.0
flutter·交互
遝靑7 小时前
Flutter 状态管理深度解析:Provider 与 Riverpod 核心原理及实战对比
flutter
小a杰.8 小时前
Flutter 图片内存优化指南(完整版)
jvm·flutter
鹏多多8 小时前
flutter使用package_info_plus库获取应用信息的教程
android·前端·flutter
走在路上的菜鸟8 小时前
Android学Dart学习笔记第十五节 类
android·笔记·学习·flutter
BigPomme8 小时前
Flutter IOS 出现实机运行问题和transpoter传包异常
flutter·ios