使用GetX结合MVC架构的Flutter项目推荐目录结构咨询
Flutter GetX + MVC 项目结构最佳实践
以下是结合GetX状态管理、路由、依赖注入与MVC架构的可扩展项目组织方案,直接落地性强:
核心目录结构示例
lib/ ├── core/ # 全局通用层(跨模块复用代码) │ ├── bindings/ # 全局依赖绑定 │ ├── constants/ # 常量、枚举、配置项 │ ├── routes/ # 路由集中配置 │ ├── services/ # 通用服务(网络、存储、主题) │ └── widgets/ # 全局复用UI组件 ├── features/ # 业务功能模块层(按功能划分) │ ├── auth/ # 认证模块(登录/注册) │ │ ├── bindings/ # 模块专属依赖绑定 │ │ ├── controllers/ # GetxController类 │ │ │ └── auth_controller.dart │ │ ├── models/ # 数据模型 │ │ │ └── user_model.dart │ │ └── views/ # UI页面/组件 │ │ ├── login_view.dart │ │ └── register_view.dart │ └── dashboard/ # 仪表盘模块 │ ├── bindings/ │ ├── controllers/ │ │ └── dashboard_controller.dart │ ├── models/ │ │ └── stats_model.dart │ └── views/ │ └── dashboard_view.dart └── main.dart
1. Models、Views、Controllers 存放规则
- Models:
- 业务专属模型放在对应功能模块的
models目录下(如auth/models/user_model.dart),仅服务当前模块业务 - 跨模块通用基础模型(如
BaseResponse、PaginationModel)抽至core/models目录
- 业务专属模型放在对应功能模块的
- Views:
- 模块专属页面/局部组件放在对应模块的
views目录(如auth/views/login_view.dart) - 全局复用组件(如自定义按钮、加载弹窗)放在
core/widgets目录
- 模块专属页面/局部组件放在对应模块的
- Controllers:
- 每个业务模块对应独立的
GetxController,放在模块的controllers目录(如auth/controllers/auth_controller.dart),仅处理当前模块的状态与业务逻辑 - 全局通用控制器(如主题切换、语言控制器)放在
core/controllers目录
- 每个业务模块对应独立的
2. 路由与绑定的组织方式
路由配置
在core/routes下拆分路由配置,避免单个文件臃肿:
// core/routes/app_routes.dart import 'package:get/get.dart'; import 'auth_routes.dart'; import 'dashboard_routes.dart'; class AppRoutes { // 全局路由名称常量 static const String initial = '/login'; // 合并所有模块路由 static final List<GetPage> pages = [ ...AuthRoutes.pages, ...DashboardRoutes.pages, ]; } // core/routes/auth_routes.dart import 'package:get/get.dart'; import '../../features/auth/views/login_view.dart'; import '../../features/auth/bindings/auth_binding.dart'; class AuthRoutes { static const String login = '/login'; static const String register = '/register'; static final List<GetPage> pages = [ GetPage( name: login, page: () => const LoginView(), binding: AuthBinding(), // 绑定模块依赖 ), GetPage( name: register, page: () => const RegisterView(), binding: AuthBinding(), ), ]; }
在main.dart中加载路由:
// main.dart import 'package:get/get.dart'; import 'core/routes/app_routes.dart'; import 'core/bindings/global_binding.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return GetMaterialApp( title: 'GetX MVC Demo', initialRoute: AppRoutes.initial, getPages: AppRoutes.pages, initialBinding: GlobalBinding(), // 全局依赖绑定 ); } }
依赖绑定(Bindings)
- 模块绑定:每个业务模块创建独立的
Binding类,放在模块的bindings目录,仅注入当前模块所需依赖:
// features/auth/bindings/auth_binding.dart import 'package:get/get.dart'; import '../controllers/auth_controller.dart'; import '../services/auth_service.dart'; class AuthBinding extends Bindings { @override void dependencies() { // 懒加载依赖,仅在需要时初始化 Get.lazyPut<AuthService>(() => AuthServiceImpl()); Get.lazyPut<AuthController>(() => AuthController(Get.find())); } }
- 全局绑定:处理跨模块通用依赖(如网络服务、本地存储),放在
core/bindings/global_binding.dart,通过initialBinding全局注入。
3. 功能扩展时的维护方案
- 严格模块化拆分:新增功能时,直接在
features下创建新模块目录(如cart、orders),内部沿用bindings/controllers/models/views结构,与其他模块完全解耦 - 通用逻辑抽离:将重复代码(如网络请求封装、日期工具类)抽至
core层,所有模块统一依赖,避免重复实现 - 路由与绑定解耦:新增模块时,单独创建对应模块的路由文件(如
core/routes/cart_routes.dart),再合并到app_routes.dart,避免单个路由文件过载 - 测试友好设计:每个模块的
Controller和Model独立,测试时可通过Get.put()注入Mock依赖,无需依赖整个应用环境 - 避免全局状态滥用:仅将真正需要全局共享的状态(如用户信息、主题)放在
core层控制器,业务模块状态由自身控制器管理
内容的提问来源于stack exchange,提问作者Navya Narayanan
相关产品推荐
相关产品推荐

