7.2 KiB
7.2 KiB
部门课 08:项目组织与 MVVM 架构入门
教学目标
- 认识 SwiftUI App 入口、根页面、功能页面、子组件、模型、状态对象和资源分别承担什么作用。
- 理解项目组织的核心是让职责和依赖清楚,而不是建立固定数量的文件夹。
- 正式理解 MVVM 的三类职责:
- Model 保存业务数据和规则;
- View 负责显示状态并传递用户操作;
- ViewModel 管理页面需要的状态和操作,连接 Model 与 View。
- 能追踪以下数据流:
用户操作
→ View 传递意图
→ ViewModel 处理操作
→ Model 或业务状态改变
→ ViewModel 发布新状态
→ View 更新
- 认识
ObservableObject、@Published、@StateObject和@ObservedObject在本课拟采用的 MVVM 写法中的基本职责,Treversi 中的实际对应关系在备课时核对,不展开底层发布机制。 - 知道状态对象应有清楚的所有者,接收者只观察同一个对象,不随意建立重复的事实来源。
- 能初步判断一段代码更适合放在 Model、ViewModel 还是 View。
- 认识小项目可以按代码角色组织,较大项目也可以按 Game、Settings 等功能组织。
- 知道 MVVM 是一种常用选择,不是 SwiftUI 或所有 App 强制采用的唯一架构。
- 能在保持功能正常的前提下逐步拆分旧项目,并在每一步重新 Build/Run。
授课干部后续备课时可参考 Apple 的 App organization 和 Managing model data in your app。
教学内容
本节采用 Demo 讲解型。授课干部先运行作为课程案例的 Treversi 游戏,再从完整产品反向阅读项目结构和一次真实的数据流。课堂主要讲授:
- 认识
TreversiApp.swift、资源文件、Core、Features 和 UI 等项目组成,以及 App 入口、页面、组件、模型、状态和资源之间的关系。 - 区分“代码角色”和“目录结构”:MVVM 描述职责与依赖,Core、Features、UI 等目录描述工程中的组织方式,两者不是同一件事。
- 从 Treversi 中寻找三类职责:
- 棋盘、玩家、配置和规则等 Model;
- 游戏状态、设置预览状态和操作处理等 ViewModel 职责;
- 棋盘、游戏、菜单和设置页面等 View。
- 追踪一次“玩家点击合法落子位置”的完整链路:View 接收点击,状态对象处理落子意图,游戏规则和模型改变,可观察状态更新,棋盘 View 重新显示。
- 结合源码实际写法认识:
ObservableObject表示可被观察的状态对象;@Published标记会驱动界面变化的状态;@StateObject用于当前 View 创建并拥有的对象;@ObservedObject用于接收并观察外部已有对象。
- 比较两种常见的项目组织思路:
- 小项目按
Models / ViewModels / Views / Resources等代码角色分类; - 较大项目按 Feature 分组,并保留 Core 和共享 UI。
- 小项目按
- 讨论何时值得拆分:某段代码已有独立职责、组件会被重复使用、页面同时混入大量显示与业务规则,或者修改功能时已经难以判断代码应该放在哪里。
- 给出旧项目的渐进重构顺序:
- 先记录并运行原始行为;
- 标出数据、操作、规则和界面;
- 先提取 Model;
- 再建立 ViewModel 并移动状态与操作;
- 让 View 主要读取状态并传递意图;
- 最后整理文件和目录;
- 每移动一步就重新 Build/Run。
- 简要介绍 MVC、MVI、Redux、TCA 和 Clean Architecture 的存在,只说明它们提供了不同的职责划分或状态管理方法,不比较优劣,也不要求记忆。
Treversi 只作为真实工程阅读案例。授课干部在备课阶段取得真实源码并核对 GameState、PreviewBoardState 等类型和观察关系,再确定最终课堂图示和讲解口径。
本节不讲协议抽象、依赖注入、Service、Repository、Coordinator、复杂路由、单元测试、Mock、测试驱动开发、多 Target、Swift Package 或工程模块化,也不展开 Clean Architecture、TCA 等其他架构的具体代码。不要求所有页面机械地套入 ViewModel,不以文件数量、文件夹层级或代码行数判断架构质量。
课后作业
作业方向为“整理我的旧作品”。具体提交目录、分支、Commit、PR 标题和截止时间以后写入独立的课后作业文档。
最低完成标准
- 优先选择部门课 4“小植物补水卡”或部门课 6“主题清单”;没有合适旧作品时,可以使用授课干部以后提供的备用项目。
- 重构前先确认原项目能够 Build/Run。
- 根据项目内容建立清楚的 Model、ViewModel 和 View 职责。
- 将主要职责拆入不同 Swift 文件,并使用自己能够理解的命名和目录组织。
- ViewModel 按课堂确认的 Treversi 观察方式连接 View。
- View 主要负责界面显示和传递用户意图,不继续保存主要业务规则。
- Model 不依赖具体 View。
- 重构后原有核心操作仍然正常运行。
- 完成至少一处可见修改,并能指出这项修改分别影响了哪个层次。
- 能简要追踪一次:
用户操作
→ View
→ ViewModel
→ Model 或状态
→ View 更新
达到最低标准即可,不要求把项目改造成正式工程,也不要求目录与授课干部示例完全一致。
建议完成标准
鼓励根据兴趣选择一项或多项尝试:
- 将重复界面拆成独立子 View。
- 在角色分类的基础上尝试按 Feature 组织文件。
- 为 ViewModel 增加一个范围明确的新操作。
- 画一张简单的项目职责图或数据流图。
- 比较传统
ObservableObject写法与现代@Observable的差异。 - 请 AI 检查某段代码是否放错职责,但由自己决定是否调整并重新运行。
建议内容不影响基础作业通过。
验收方式
- 学员通过个人 Fork 和作业分支向部门公开仓库提交完整项目源码 PR。
- 授课干部取得源码后确认项目能够 Build/Run,重构前后的核心行为一致。
- PR 中简要说明:
- 哪些文件属于 Model、ViewModel 和 View;
- ViewModel 拥有哪些状态和操作;
- 一次用户操作怎样经过三层并更新界面;
- 自己完成了哪一处可见修改。
- 如需证明互动效果,可以通过约定渠道发送简短运行视频,不规定视频格式和编码。
- 结合本课 PR 和作业反馈确认职责划分与操作链,不把技术抽查安排到部门课 09。
- 简短说明不完整时给予反馈,不因表达不够准确拒绝已达到基础要求的作品,也不安排逐人技术答辩、排名或淘汰。
- 未完成时允许提交 Draft PR,记录当前结构、完整错误和已经尝试的步骤。
- 不以文件数量、目录是否与授课干部完全一致、是否使用高级抽象或能否背诵其他架构作为通过门槛。
源码提交、工具故障时的参与记录和隐私边界按共同安排执行;具体材料与操作细节由授课干部在备课阶段准备。