# 为什么 PageViewModelFactory 必须在 Presentation 层? ## 🎯 核心原因 **PageViewModelFactory 直接依赖 Presentation 层的 ViewModel 类型!** ## 📊 依赖关系分析 ### 依赖链 1:PageViewModelFactory → ViewModels ``` AuroraDesk.Core.Interfaces.IPageViewModelFactory (接口定义) ↑ | 实现 | AuroraDesk.Presentation.Services.PageViewModelFactory ↓ 依赖 [必须知道具体的 ViewModel 类型] - DashboardPageViewModel - UsersPageViewModel - SettingsPageViewModel - ReportsPageViewModel - ... (所有 PageViewModel) ``` ### 关键代码 ```csharp // AuroraDesk.Presentation/Services/PageViewModelFactory.cs // ❌ 这里必须引用具体的 ViewModel 类型! using AuroraDesk.Presentation.ViewModels.Pages; // ← 关键! using AuroraDesk.Core.Interfaces; // 接口定义 public class PageViewModelFactory : IPageViewModelFactory { public IRoutableViewModel CreatePageViewModel(string pageId, IScreen screen) { return pageId switch { "dashboard" => CreatePageViewModel(screen), // ← 需要具体的 ViewModel 类型 "users" => CreatePageViewModel(screen), "settings" => CreatePageViewModel(screen), // ... }; } } ``` ## 🚫 为什么不放在其他层? ### 方案1:放在 Infrastructure 层? ❌ ``` AuroraDesk.Infrastructure.Services.PageViewModelFactory ↓ 依赖 AuroraDesk.Presentation.ViewModels.Pages.* // ❌ 违反依赖倒置! ``` **问题**: - Infrastructure 不能依赖 Presentation - 违反了整洁架构的依赖规则 - 会导致循环依赖 ### 方案2:放在主项目(AuroraDesk)? ⚠️ ``` AuroraDesk/Services/PageViewModelFactory.cs ↓ 依赖 AuroraDesk.Presentation.ViewModels.Pages.* // ✅ 可以 ``` **优点**: - 主项目可以访问所有层 - 符合依赖规则 **缺点**: - 主项目会变得臃肿 - 降低了分层清晰度 - 当前架构中,主项目主要用于启动配置 ### 方案3:放在 Presentation 层? ✅ ``` AuroraDesk.Presentation.Services.PageViewModelFactory ↓ 依赖 AuroraDesk.Presentation.ViewModels.Pages.* // ✅ 同层,完全合理! ``` **优点**: - ✅ 在同一层,无需跨层依赖 - ✅ 职责清晰:Presentation 层管理所有 UI 相关组件 - ✅ 符合依赖倒置:实现 Core 的接口,使用同一层的类型 ## 📚 依赖倒置原则(DIP)解析 ### 什么是依赖倒置? **高层模块不应该依赖低层模块,两者都应该依赖抽象。** ### 在我们的架构中 ``` 高层(Presentation) 低层(Infrastructure) ↓ ↓ 使用接口(IPageViewModelFactory) ← 实现接口(但在不同层) ↓ ↓ 使用具体类型(DashboardPageViewModel) ← 这是 Presentation 层内部的事 ``` **关键理解**: 1. ✅ **接口在 Core 层定义**(IPageViewModelFactory) 2. ✅ **实现可以在 Presentation 层**(PageViewModelFactory) 3. ✅ **使用同层的具体类型**(DashboardPageViewModel) 这并不违反依赖倒置,因为: - 依赖方向是:Presentation → Core(接口) - Presentation 使用自己的类型,这是正常的 ## 🔍 对比其他服务和工厂 ### NavigationService(Infrastructure 层) ``` AuroraDesk.Infrastructure.Services.NavigationService ↓ 依赖 AuroraDesk.Core.Interfaces.IPageViewModelFactory // ✅ 只依赖接口 AuroraDesk.Core.Entities.NavigationItem // ✅ 依赖 Core 层 ``` **为什么可以?** 因为它只使用接口,不依赖具体的 ViewModel 类型! ### 如果 PageViewModelFactory 没有页面的具体类型? 假设我们有一个"抽象"的工厂: ```csharp // 假设:不使用具体的 ViewModel 类型 public interface IPageViewModelFactory { // 只返回接口,不涉及具体类型 IRoutableViewModel CreatePageViewModel(string pageId, IScreen screen); } ``` **问题**:那工厂内部如何创建具体的 ViewModel? - ❌ 如果不用具体类型,就必须用反射 - ❌ 失去了编译时类型检查 - ❌ 需要维护复杂的映射配置 这就是为什么工厂通常依赖具体类型! ## ✅ 结论 **PageViewModelFactory 在 Presentation 层是正确的!** ### 依赖关系图 ``` ┌─────────────────────────────────────────┐ │ Core (核心层) │ │ - Interfaces/IPageViewModelFactory │ ← 接口定义 └─────────────────────────────────────────┘ ↑ 依赖 ↑ 依赖 | | ┌─────────────────────────┐ ┌──────────────────────────┐ │ Presentation │ │ Infrastructure │ │ - Services/ │ │ - Services/ │ │ PageViewModelFactory │ │ NavigationService │ │ ↓ 实现接口 │ │ ↓ 使用接口 │ │ - ViewModels/Pages/ │ │ │ │ DashboardPage... │ │ │ │ UsersPage... │ │ │ └─────────────────────────┘ └──────────────────────────┘ ↑ | PageViewModelFactory 使用 | DashboardPageViewModel, UsersPageViewModel, etc. ``` **为什么合理?** 1. ✅ `PageViewModelFactory` 实现了 Core 的接口 2. ✅ `PageViewModelFactory` 使用 Presentation 层的类型 3. ✅ 两者在同一层,没有跨层依赖问题 4. ✅ Infrastructure 层通过接口使用,不依赖具体实现 ## 📋 总结 | 位置 | 是否合理 | 原因 | |------|---------|------| | **Infrastructure** | ❌ | 违反依赖规则(Infrastructure → Presentation) | | **Core** | ❌ | 违反依赖规则(Core 不能依赖其他层) | | **Application** | ❌ | Application 不能依赖 UI 层类型 | | **主项目** | ⚠️ | 可行,但会让主项目臃肿 | | **Presentation** | ✅ | 合理!与 ViewModels 同层,实现 Core 接口 | **所以,您说得完全正确!** 🎉