网站聊天工具代码,网页设计师培训费用图,图片在线制作免费软件,公共资源交易中心是事业单位吗拒绝“面条代码”#xff01;Flutter 校园项目的“三层架构”实战
作为一名计算机专业的学生#xff0c;你是否遇到过这种情况#xff1a; 为了赶课程设计或hackathon#xff0c;在 StatefulWidget 的 build 方法里直接写 Dio.get #xff0c;把网络请求、JSON解析、UI更…拒绝“面条代码”Flutter 校园项目的“三层架构”实战作为一名计算机专业的学生你是否遇到过这种情况为了赶课程设计或hackathon在 StatefulWidget 的 build 方法里直接写 Dio.get 把网络请求、JSON解析、UI更新全都堆在一起。结果项目刚写到一半代码就乱成了“意大利面”改一个接口字段要在几百行代码里找半天队友看了想打人。最近重构校园跑腿 App 时我痛定思痛引入了三层架构Repository ViewModel UI的思想配合 GetX 状态管理终于把代码理顺了。这篇文章我想分享这套适合大学生项目的**“清爽开发模式”**。一、 什么是“三层架构”简单来说就是把我们的代码像切蛋糕一样分成三块各司其职数据层 (Repository/Model)只管“拿数据”。负责对接后端 API解析 JSON或者读写本地缓存。它不知道谁在调用它。逻辑层 (ViewModel/Controller)只管“处理数据”。负责接收 UI 的指令调用数据层处理业务逻辑比如判断登录状态然后通知 UI 更新。表现层 (UI/View)只管“展示”。它不包含复杂逻辑只负责把 ViewModel 给的数据画在屏幕上并在用户点击按钮时通知 ViewModel。二、 代码实战校园登录功能的“整容”过程下面我用一个最常见的**“校园账号登录”**功能展示如何用这套架构重写代码。第一步定义数据模型 (Model)先定义好数据的结构这里使用 json_serializable 插件自动生成强烈推荐别手写 fromJson 。dart// models/user.dartimport ‘package:json_annotation/json_annotation.dart’;part ‘user.g.dart’;JsonSerializable()class User {final String studentId;final String name;final String token;User({required this.studentId, required this.name, required this.token});// 自动生成的代码factory User.fromJson(MapString, dynamic json) _$UserFromJson(json);}第二步数据仓库 (Repository)专门处理网络请求这里我使用 Dio 。dart// repositories/auth_repository.dartimport ‘package:dio/dio.dart’;import ‘…/models/user.dart’;class AuthRepository {final Dio _dio Dio();// 登录请求只关心参数和返回值不关心UIFuture login(String id, String password) async {try {final response await _dio.post(“https://api.campus.com/login”,data: {“student_id”: id, “password”: password},);// 直接返回模型对象让调用者省心return User.fromJson(response.data[‘data’]);} catch (e) {// 抛出异常让上层处理throw Exception(“登录失败: $e”);}}}第三步业务逻辑 (ViewModel/Controller)这是核心我使用 GetxController 。它像一个中间人隔离了 UI 和数据。dart// controllers/login_controller.dartimport ‘package:get/get.dart’;import ‘…/repositories/auth_repository.dart’;import ‘…/models/user.dart’;class LoginController extends GetxController {// 1. 依赖注入仓库final AuthRepository _repo AuthRepository();// 2. 定义可观测状态UI 可以监听这些变量var isLoading false.obs;var errorMessage “”.obs;// 3. 业务方法UI 调用这个方法Future handleLogin(String id, String pwd) async {isLoading.value true;errorMessage.value “”;try { User user await _repo.login(id, pwd); // 登录成功后的逻辑保存 Token、跳转页面 GetStorage().write(token, user.token); Get.offAllNamed(/home); // 路由跳转 } catch (e) { errorMessage.value e.toString(); } finally { isLoading.value false; }}}第四步清爽的 UI 层UI 层现在变得非常干净没有任何 async/await 网络代码。dart// pages/login_page.dartimport ‘package:flutter/material.dart’;import ‘package:get/get.dart’;import ‘…/controllers/login_controller.dart’;class LoginPage extends StatelessWidget {// 获取控制器final LoginController _controller Get.put(LoginController());overrideWidget build(BuildContext context) {return Scaffold(body: Padding(padding: EdgeInsets.all(20),child: Column(children: [TextField(decoration: InputDecoration(labelText: “学号”),// … 省略控制器绑定),TextField(decoration: InputDecoration(labelText: “密码”),obscureText: true,),SizedBox(height: 20),// 监听状态变化Obx(() _controller.isLoading.value? CircularProgressIndicator(): ElevatedButton(onPressed: () _controller.handleLogin(“2023001”, “123456”),child: Text(“登录”))),// 错误提示Obx(() Text(_controller.errorMessage.value,style: TextStyle(color: Colors.red),))],),),);}}三、 这样做的好处为什么要折腾代码复用如果我在“个人中心”也需要用到登录接口直接调用 AuthRepository 即可不用复制粘贴代码。便于测试如果后端接口挂了我想测试 UI 表现只需要在 ViewModel 里模拟一个返回数据完全不用动 UI 代码。面试亮点当面试官问你“如何处理网络请求”时如果你能说出“我会分层处理使用 Repository 模式隔离数据源”这比说“我直接在 initState 里写 Dio.get ”要高级得多。四、 给同学们的建议对于校园项目我们不需要追求 Google 官方那套庞大的 BLoC 模式学习曲线太陡GetX 简单的 Repository 分层 是目前性价比最高的方案。下次做课设或大作业时试着把网络请求抽离出来你会发现你的代码结构会变得像教科书一样漂亮。结语技术的成长往往不是看你会多少炫酷的特效而是看你写的代码是否“高内聚、低耦合”。希望这篇文章能帮你摆脱“代码洁癖”的困扰写出让自己和队友都舒服的 Flutter 代码