Flutter 项目结构该如何设计,才能支撑长期迭代

📅 发布时间:2026/7/17 8:50:05 👁️ 浏览次数:
Flutter 项目结构该如何设计,才能支撑长期迭代
网罗开发小红书、快手、视频号同名大家好我是展菲目前在上市企业从事人工智能项目研发管理工作平时热衷于分享各种编程领域的软硬技能知识以及前沿技术包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。图书作者《ESP32-C3 物联网工程开发实战》图书作者《SwiftUI 入门进阶与实战》超级个体COC上海社区主理人特约讲师大学讲师谷歌亚马逊分享嘉宾科技博主华为HDE/HDG我的博客内容涵盖广泛主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告同时也会提供产品优缺点分析、横向对比并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。展菲您的前沿技术领航员 大家好我是展菲 全网搜索“展菲”即可纵览我在各大平台的知识足迹。 公众号“Swift社区”每周定时推送干货满满的技术长文从新兴框架的剖析到运维实战的复盘助您技术进阶之路畅通无阻。 微信端添加好友“fzhanfei”与我直接交流不管是项目瓶颈的求助还是行业趋势的探讨随时畅所欲言。 最新动态2025 年 3 月 17 日快来加入技术社区一起挖掘技术的无限潜能携手迈向数字化新征程文章目录前言常见 Flutter 项目结构对比页面级和业务级模块怎么划分可扩展的目录规范实际项目演进中的取舍总结前言很多 Flutter 项目一开始目录挺整齐按「页面」「模型」「服务」一分看起来挺好维护。可随着功能越加越多改一处要动好几个文件夹、新人看半天不知道从哪下手、加个新需求总怕踩到老代码的雷。本质上是结构没按「长期迭代」来设计只满足了「当下能跑」。要支撑长期迭代就得在目录划分、模块边界和扩展规范上想清楚让每个改动都有明确归属新人也能按图索骥。下面从常见结构对比、页面级和业务级怎么切、可扩展的目录规范、以及实际演进中的取舍几方面说一下。常见 Flutter 项目结构对比最常见的有两种思路按「类型」分type-first和按「功能/业务」分feature-first。按类型分就是大家熟悉的lib/下models/、views/、services/、utils/这种。所有模型放一起、所有页面放一起、所有接口放一起。好处是刚上手简单找「所有接口」或「所有页面」很快。问题在于一个业务比如「订单」的模型、页面、接口、状态会散在四个目录里改一个需求要到处跳职责也容易混——services里既有订单接口又有用户接口时间一长就变成大杂烩新人很难判断「这段逻辑该放哪」。按功能/业务分Feature First则是按业务域或功能块建目录每个功能块里再放自己的页面、模型、接口、状态。例如lib/features/order/、lib/features/user/每个 feature 下面再分screens/、widgets/、models/、services/等。这样「订单相关」的改动基本都在order下完成边界清晰新人接手也容易先找 feature再在 feature 里找具体文件。代价是前期要定好「哪些算一个 feature」避免 feature 划分过细或过粗。实际项目里往往不会非此即彼核心、会长期演进的业务用 Feature First真正全局的通用能力如网络封装、路由、通用组件单独抽成 shared 或 core这样既避免「全按类型」导致的扩散也避免「全按 feature」导致公共层缺失。页面级和业务级模块怎么划分「模块」可以按粒度拆成两种页面级和业务级。页面级以「一个或一组相关页面」为单位。比如「订单列表」「订单详情」「订单创建」算一个订单模块里面主要是 UI、页面状态和该页用到的接口。适合功能相对独立、复用面不大的场景。划分时建议一个模块一个目录里面再按screens/、widgets/、providers/或bloc/等分层避免一个文件上千行。业务级比页面大一层是「一整块业务」订单从列表、详情、创建、支付、售后都算订单业务可能跨多个页面、甚至多个 Tab。业务级模块里会包含多个页面级子模块以及该业务共用的模型、领域逻辑、接口。划分业务级的意义在于把「会一起变、一起发版」的东西收拢减少跨模块的随意依赖。比如订单和商品是两条业务线订单模块可以依赖「商品」的少量接口或模型但不要反过来让订单逻辑散进商品模块。实践中先按业务级划出几个大目录如 order、user、product再在业务内部按页面或子功能划子目录。这样既不会一上来就几十个平级目录也不会所有代码挤在少数几个文件夹里。可扩展的目录规范要支撑长期迭代目录不能只满足「现在」还要约定「以后怎么加」。建议定几条简单规范第一统一命名和层级。例如每个 feature 下都允许有screens/、widgets/、models/、services/或你项目用的分层新增时只在这几类里加不随意在 feature 根目录堆新名字。这样任何人一看就知道「新页面放 screens新接口放 services」。第二公共能力单独成层。如lib/core/或lib/shared/放网络、路由、存储、通用 UI 组件、常量等。feature 只依赖 core/shared不互相依赖core 不依赖具体 feature。这样以后加新 feature 或换掉某个业务不会牵一发动全身。第三约定「入口」。每个 feature 尽量有一个index.dart或明确入口文件对外只 export 需要被路由或其它模块引用的部分内部实现细节不暴露。这样依赖关系清晰重构时也容易缩小影响面。第四文档化。在项目根目录或lib/下放一个简单的STRUCTURE.md说明「业务模块有哪些、公共层放什么、新加一个 feature 要建哪些目录、命名约定」。新人按文档操作即可减少「随便建个文件夹」的随意性。一个可参考的目录示例按上述规范收敛后可以长这样lib/ ├── core/ # 公共层被各 feature 依赖 │ ├── network/ │ ├── router/ │ ├── storage/ │ └── widgets/ # 通用按钮、弹窗等 ├── features/ │ ├── order/ │ │ ├── screens/ # 订单列表、详情、创建等页 │ │ ├── widgets/ # 订单相关卡片、表单等 │ │ ├── models/ │ │ ├── services/ │ │ └── index.dart # 只 export 路由需要的 Page、对外模型 │ ├── user/ │ │ ├── screens/ │ │ ├── widgets/ │ │ ├── models/ │ │ ├── services/ │ │ └── index.dart │ └── product/ │ └── ... └── app.dart # 入口注册路由、主题等解析core里不放业务逻辑只放「大家都要用」的能力这样新加或替换某个 feature 时不会动到 core。每个 feature 内部结构一致screens/widgets/models/services新人加「订单下的新页」就知道去order/screens/新建文件。index.dart只对外暴露路由用到的页面和少量对外模型避免其它模块直接import order/xxx/internal.dart以后改内部实现不会波及全局。按这种约定扩展长期迭代时改动的范围更容易控制。实际项目演进中的取舍真实项目里很少能从零就按「理想结构」来多半是边做边收拢。初期功能少、人少用类型分models/views/services就能跑。这时不必强行上 Feature First但可以约定新增功能时尽量在一个「功能子目录」下集中放例如views/order/、services/order/为以后拆成独立 feature 留余地。中期功能多了、改一处动多处的情况开始出现就可以选 12 个最核心、最常改的业务先拆成 feature 目录把相关页面、模型、接口都迁进去。其它暂时保持原样用「新代码按新结构、老代码逐步迁」的方式演进避免一次性大重构。长期核心业务都进 feature公共能力稳定在 core/shared再配合「入口 export」和依赖方向约定feature 不互相依赖就能比较稳地支撑长期迭代。遇到「这段到底算哪个 feature」的争议以「谁改得多、谁负责」为准来归属再慢慢用边界清晰化。总结Flutter 项目要支撑长期迭代结构上建议用 Feature First 收拢业务用 core/shared 收拢公共能力区分清楚页面级和业务级模块先按业务划大目录再在内部按页面或子功能细分并约定好目录层级、命名、入口和依赖方向再配一份简短的结构说明文档。这样初期不会过度设计后期也有清晰的扩展路径改起来敢动、新人接手成本也会低很多。