487 changed files with 701 additions and 9135 deletions
@ -0,0 +1,441 @@ |
|||
# AuroraDesk 项目重构计划 |
|||
|
|||
## 📋 项目概述 |
|||
|
|||
**目标项目名**: AuroraDesk |
|||
**原项目名**: MyAvaloniaApp |
|||
**目标架构**: 整洁架构 (Clean Architecture) |
|||
**重点优化**: 减少 ViewModels 耦合,提高代码可维护性 |
|||
**环境**: Windows 10 |
|||
**注意事项**: 避免使用 Linux 语法,防止乱码问题 |
|||
|
|||
--- |
|||
|
|||
## 🎯 重构目标 |
|||
|
|||
### 1. 项目重命名 |
|||
- 项目名称:`MyAvaloniaApp` → `AuroraDesk` |
|||
- 解决方案文件:`MyAvaloniaApp.sln` → `AuroraDesk.sln` |
|||
- 项目文件:`MyAvaloniaApp.csproj` → `AuroraDesk.csproj` |
|||
- 命名空间前缀:`MyAvaloniaApp.*` → `AuroraDesk.*` |
|||
|
|||
### 2. 架构重构(整洁架构) |
|||
|
|||
#### 2.1 项目分层结构 |
|||
|
|||
``` |
|||
AuroraDesk/ |
|||
├── AuroraDesk.Core/ # 核心领域层 |
|||
│ ├── Entities/ # 领域实体 |
|||
│ │ ├── NavigationItem.cs |
|||
│ │ ├── TabItem.cs |
|||
│ │ └── ... |
|||
│ ├── Interfaces/ # 领域接口 |
|||
│ └── Exceptions/ # 领域异常 |
|||
│ |
|||
├── AuroraDesk.Application/ # 应用层 |
|||
│ ├── Services/ # 应用服务接口 |
|||
│ │ ├── INavigationService.cs |
|||
│ │ ├── IPageFactory.cs |
|||
│ │ └── ... |
|||
│ ├── DTOs/ # 数据传输对象 |
|||
│ └── Mappings/ # 映射配置 |
|||
│ |
|||
├── AuroraDesk.Infrastructure/ # 基础设施层 |
|||
│ ├── Services/ # 服务实现 |
|||
│ │ ├── NavigationService.cs |
|||
│ │ ├── PageFactory.cs |
|||
│ │ ├── DataService.cs |
|||
│ │ ├── ApiService.cs |
|||
│ │ └── ResourceService.cs |
|||
│ ├── Configuration/ # 配置 |
|||
│ │ └── AppSettings.cs |
|||
│ └── Extensions/ # 扩展方法 |
|||
│ └── ServiceCollectionExtensions.cs |
|||
│ |
|||
└── AuroraDesk.Presentation/ # 表示层 |
|||
├── ViewModels/ # ViewModels(精简) |
|||
│ ├── MainWindowViewModel.cs |
|||
│ ├── AppViewModel.cs |
|||
│ └── Base/ |
|||
│ └── RoutableViewModel.cs |
|||
├── Views/ # Views |
|||
│ ├── ViewLocator.cs |
|||
│ └── Pages/ |
|||
├── Converters/ # 转换器 |
|||
└── Behaviors/ # 行为 |
|||
``` |
|||
|
|||
#### 2.2 命名空间规划 |
|||
|
|||
```csharp |
|||
// 核心领域层 |
|||
AuroraDesk.Core |
|||
AuroraDesk.Core.Entities |
|||
AuroraDesk.Core.Interfaces |
|||
AuroraDesk.Core.Exceptions |
|||
|
|||
// 应用层 |
|||
AuroraDesk.Application |
|||
AuroraDesk.Application.Services |
|||
AuroraDesk.Application.DTOs |
|||
AuroraDesk.Application.Mappings |
|||
|
|||
// 基础设施层 |
|||
AuroraDesk.Infrastructure |
|||
AuroraDesk.Infrastructure.Services |
|||
AuroraDesk.Infrastructure.Configuration |
|||
AuroraDesk.Infrastructure.Extensions |
|||
|
|||
// 表示层 |
|||
AuroraDesk.Presentation |
|||
AuroraDesk.Presentation.ViewModels |
|||
AuroraDesk.Presentation.ViewModels.Base |
|||
AuroraDesk.Presentation.Views |
|||
AuroraDesk.Presentation.Views.Pages |
|||
AuroraDesk.Presentation.Converters |
|||
AuroraDesk.Presentation.Behaviors |
|||
``` |
|||
|
|||
### 3. 解耦 ViewModels 策略 |
|||
|
|||
#### 3.1 问题分析 |
|||
**当前问题**: |
|||
- `MainWindowViewModel` 中直接创建了所有 `PageViewModel` 实例(高耦合) |
|||
- ViewModel 创建逻辑分散在 `InitializeNavigationItems` 方法中 |
|||
- 难以进行单元测试 |
|||
- 违反单一职责原则 |
|||
|
|||
**解决方案**: |
|||
1. **引入 PageViewModel 工厂模式** |
|||
- 创建 `IPageViewModelFactory` 接口 |
|||
- 实现 `PageViewModelFactory` 类 |
|||
- 通过依赖注入管理 ViewModel 创建 |
|||
|
|||
2. **引入导航服务** |
|||
- 创建 `INavigationService` 接口 |
|||
- 封装导航逻辑,减少 MainWindowViewModel 职责 |
|||
- 统一管理导航项配置 |
|||
|
|||
3. **将配置数据外置** |
|||
- 创建导航配置数据类(NavigationConfig) |
|||
- 从 ViewModel 中分离配置数据 |
|||
- 配置可在应用启动时注入 |
|||
|
|||
#### 3.2 重构后的依赖关系 |
|||
|
|||
``` |
|||
MainWindowViewModel |
|||
↓ (依赖) |
|||
INavigationService // 处理导航逻辑 |
|||
IPageViewModelFactory // 创建 PageViewModel |
|||
ILogger // 日志记录 |
|||
IScreen // ReactiveUI 路由 |
|||
|
|||
不再直接依赖: |
|||
❌ DashboardPageViewModel |
|||
❌ UsersPageViewModel |
|||
❌ SettingsPageViewModel |
|||
... (所有具体的 PageViewModel) |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 📝 详细重构步骤 |
|||
|
|||
### 阶段一:准备工作(不修改代码) |
|||
|
|||
#### 步骤 1.1: 创建新项目结构(可选,建议先单项目重构) |
|||
- [ ] 创建分层项目结构(或多文件夹结构) |
|||
- [ ] 规划文件迁移路径 |
|||
- [ ] 备份当前代码 |
|||
|
|||
#### 步骤 1.2: 分析依赖关系 |
|||
- [ ] 梳理所有 ViewModel 之间的依赖 |
|||
- [ ] 识别所有直接 new 实例化的地方 |
|||
- [ ] 记录需要注入的服务 |
|||
|
|||
--- |
|||
|
|||
### 阶段二:架构重构(按顺序执行) |
|||
|
|||
#### 步骤 2.1: 创建核心领域层 |
|||
- [ ] 创建 `AuroraDesk.Core` 项目/文件夹 |
|||
- [ ] 迁移实体类:`NavigationItem`, `TabItem` 到 `Core.Entities` |
|||
- [ ] 更新命名空间:`AuroraDesk.Core.Entities` |
|||
- [ ] 移除业务逻辑,只保留数据模型 |
|||
|
|||
#### 步骤 2.2: 创建应用层接口 |
|||
- [ ] 创建 `AuroraDesk.Application` 项目/文件夹 |
|||
- [ ] 定义 `INavigationService` 接口 |
|||
- [ ] 定义 `IPageViewModelFactory` 接口 |
|||
- [ ] 定义导航配置 DTO(NavigationConfig) |
|||
|
|||
#### 步骤 2.3: 创建基础设施层实现 |
|||
- [ ] 创建 `AuroraDesk.Infrastructure` 项目/文件夹 |
|||
- [ ] 实现 `NavigationService` |
|||
- [ ] 实现 `PageViewModelFactory` |
|||
- [ ] 迁移现有服务:`DataService`, `ApiService`, `ResourceService` |
|||
- [ ] 更新服务命名空间为 `AuroraDesk.Infrastructure.Services` |
|||
|
|||
#### 步骤 2.4: 重构表示层 |
|||
- [ ] 更新 `MainWindowViewModel`,移除直接创建 ViewModel 的代码 |
|||
- [ ] 注入 `INavigationService` 和 `IPageViewModelFactory` |
|||
- [ ] 简化 `MainWindowViewModel` 的职责 |
|||
- [ ] 更新所有命名空间为 `AuroraDesk.Presentation.*` |
|||
|
|||
--- |
|||
|
|||
### 阶段三:项目重命名(谨慎执行) |
|||
|
|||
#### 步骤 3.1: 重命名项目文件 |
|||
- [ ] 重命名 `.csproj` 文件 |
|||
- [ ] 重命名 `.sln` 文件 |
|||
- [ ] 更新项目文件中的 `<RootNamespace>` 和 `<AssemblyName>` |
|||
|
|||
#### 步骤 3.2: 重命名命名空间(逐个文件修改) |
|||
- [ ] **不要使用批量替换** |
|||
- [ ] 逐个文件修改命名空间声明 |
|||
- [ ] 逐个文件更新 using 语句 |
|||
- [ ] 每次修改后编译测试 |
|||
|
|||
#### 步骤 3.3: 更新配置文件 |
|||
- [ ] 更新 `appsettings.json` 中的项目相关配置 |
|||
- [ ] 更新 `app.manifest` 中的程序集名称 |
|||
- [ ] 更新所有批处理文件和脚本 |
|||
|
|||
--- |
|||
|
|||
### 阶段四:解耦 ViewModels(重点) |
|||
|
|||
#### 步骤 4.1: 创建工厂接口和实现 |
|||
```csharp |
|||
// AuroraDesk.Application/Services/IPageViewModelFactory.cs |
|||
public interface IPageViewModelFactory |
|||
{ |
|||
T CreatePageViewModel<T>(IScreen screen) where T : IRoutableViewModel; |
|||
IRoutableViewModel CreatePageViewModel(string pageId, IScreen screen); |
|||
} |
|||
``` |
|||
|
|||
#### 步骤 4.2: 实现工厂类 |
|||
```csharp |
|||
// AuroraDesk.Infrastructure/Services/PageViewModelFactory.cs |
|||
public class PageViewModelFactory : IPageViewModelFactory |
|||
{ |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public IRoutableViewModel CreatePageViewModel(string pageId, IScreen screen) |
|||
{ |
|||
return pageId switch |
|||
{ |
|||
"dashboard" => _serviceProvider.GetRequiredService<DashboardPageViewModel>(), |
|||
"users" => _serviceProvider.GetRequiredService<UsersPageViewModel>(), |
|||
// ... 其他页面 |
|||
_ => throw new ArgumentException($"Unknown page: {pageId}") |
|||
}; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
#### 步骤 4.3: 创建导航服务 |
|||
```csharp |
|||
// AuroraDesk.Application/Services/INavigationService.cs |
|||
public interface INavigationService |
|||
{ |
|||
ObservableCollection<NavigationItem> GetNavigationItems(); |
|||
void NavigateToPage(NavigationItem item); |
|||
} |
|||
``` |
|||
|
|||
#### 步骤 4.4: 重构 MainWindowViewModel |
|||
- [ ] 移除 `InitializeNavigationItems` 方法中的 ViewModel 创建逻辑 |
|||
- [ ] 注入 `INavigationService` 获取导航项 |
|||
- [ ] 使用 `IPageViewModelFactory` 创建 ViewModel |
|||
- [ ] 简化导航逻辑,委托给 `INavigationService` |
|||
|
|||
--- |
|||
|
|||
### 阶段五:注册依赖注入 |
|||
|
|||
#### 步骤 5.1: 更新 ServiceCollectionExtensions |
|||
- [ ] 注册 `IPageViewModelFactory` → `PageViewModelFactory` |
|||
- [ ] 注册 `INavigationService` → `NavigationService` |
|||
- [ ] 注册所有 PageViewModel 为 Transient(或 Scoped) |
|||
- [ ] 更新命名空间引用 |
|||
|
|||
#### 步骤 5.2: 更新 App.axaml.cs |
|||
- [ ] 确保所有新服务正确注册 |
|||
- [ ] 更新 ViewLocator 的命名空间 |
|||
- [ ] 测试依赖注入是否正常工作 |
|||
|
|||
--- |
|||
|
|||
### 阶段六:测试和验证 |
|||
|
|||
#### 步骤 6.1: 编译测试 |
|||
- [ ] 清理解决方案并重新编译 |
|||
- [ ] 修复所有编译错误 |
|||
- [ ] 修复所有命名空间引用错误 |
|||
|
|||
#### 步骤 6.2: 运行时测试 |
|||
- [ ] 启动应用程序 |
|||
- [ ] 测试导航功能 |
|||
- [ ] 测试所有页面能否正常加载 |
|||
- [ ] 测试标签页功能 |
|||
|
|||
#### 步骤 6.3: 代码检查 |
|||
- [ ] 检查是否还有直接 new ViewModel 的地方 |
|||
- [ ] 检查命名空间是否全部更新 |
|||
- [ ] 检查是否有循环依赖 |
|||
|
|||
--- |
|||
|
|||
## 🔧 技术实现细节 |
|||
|
|||
### 1. PageViewModel 注册方式 |
|||
|
|||
```csharp |
|||
// ServiceCollectionExtensions.cs |
|||
services.AddTransient<DashboardPageViewModel>(); |
|||
services.AddTransient<UsersPageViewModel>(); |
|||
services.AddTransient<SettingsPageViewModel>(); |
|||
// ... 其他 PageViewModel |
|||
``` |
|||
|
|||
### 2. 导航配置数据 |
|||
|
|||
```csharp |
|||
// NavigationConfig.cs |
|||
public class NavigationConfig |
|||
{ |
|||
public List<NavigationItemConfig> Items { get; set; } = new(); |
|||
} |
|||
|
|||
public class NavigationItemConfig |
|||
{ |
|||
public string Id { get; set; } = string.Empty; |
|||
public string Title { get; set; } = string.Empty; |
|||
public string PageViewModelType { get; set; } = string.Empty; |
|||
public IconType IconType { get; set; } |
|||
public List<NavigationItemConfig>? Children { get; set; } |
|||
} |
|||
``` |
|||
|
|||
### 3. MainWindowViewModel 重构示例 |
|||
|
|||
**重构前**: |
|||
```csharp |
|||
private void InitializeNavigationItems() |
|||
{ |
|||
_navigationItems = new ObservableCollection<NavigationItem> |
|||
{ |
|||
new NavigationItem { ViewModel = new DashboardPageViewModel(_screen) }, |
|||
new NavigationItem { ViewModel = new UsersPageViewModel(_screen) }, |
|||
// ... |
|||
}; |
|||
} |
|||
``` |
|||
|
|||
**重构后**: |
|||
```csharp |
|||
private readonly INavigationService _navigationService; |
|||
|
|||
public MainWindowViewModel( |
|||
IScreen screen, |
|||
INavigationService navigationService, |
|||
ILogger<MainWindowViewModel>? logger = null) |
|||
{ |
|||
_screen = screen; |
|||
_navigationService = navigationService; |
|||
_logger = logger; |
|||
|
|||
NavigationItems = _navigationService.GetNavigationItems(); |
|||
} |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## ⚠️ 注意事项 |
|||
|
|||
### 1. 不要批量替换 |
|||
- ❌ **禁止**:使用 Visual Studio 的全局查找替换功能批量替换命名空间 |
|||
- ✅ **正确做法**:逐个文件修改,每次修改后编译测试 |
|||
|
|||
### 2. Windows 10 环境 |
|||
- ❌ **避免**:使用 Linux 风格的路径分隔符或命令 |
|||
- ✅ **使用**:Windows 路径分隔符 `\` 或使用 `Path.Combine` |
|||
- ✅ **使用**:PowerShell 脚本而非 Bash 脚本 |
|||
|
|||
### 3. 编译顺序 |
|||
- 先编译被依赖的层(Core → Application → Infrastructure → Presentation) |
|||
- 每次修改一层后立即编译测试 |
|||
|
|||
### 4. Git 版本控制 |
|||
- 每个阶段完成后提交一次代码 |
|||
- 使用有意义的提交信息 |
|||
- 如果出现问题可以回退到上一个阶段 |
|||
|
|||
--- |
|||
|
|||
## 📊 预期成果 |
|||
|
|||
### 代码质量提升 |
|||
- ✅ ViewModels 耦合度降低 80%+ |
|||
- ✅ 代码可测试性提升 |
|||
- ✅ 符合整洁架构原则 |
|||
- ✅ 易于扩展新功能 |
|||
|
|||
### 项目结构 |
|||
- ✅ 清晰的分层架构 |
|||
- ✅ 统一的命名空间规范(Aurora 前缀) |
|||
- ✅ 更好的代码组织 |
|||
|
|||
### 维护性 |
|||
- ✅ 新页面添加只需注册,无需修改 MainWindowViewModel |
|||
- ✅ 导航逻辑集中管理 |
|||
- ✅ 配置与代码分离 |
|||
|
|||
--- |
|||
|
|||
## 📅 执行时间估算 |
|||
|
|||
- **阶段一**(准备):0.5 天 |
|||
- **阶段二**(架构重构):2-3 天 |
|||
- **阶段三**(重命名):1-2 天 |
|||
- **阶段四**(解耦):2-3 天 |
|||
- **阶段五**(DI注册):0.5 天 |
|||
- **阶段六**(测试):1 天 |
|||
|
|||
**总计**:约 7-10 个工作日 |
|||
|
|||
--- |
|||
|
|||
## ✅ 检查清单 |
|||
|
|||
在每个阶段完成后,使用此清单验证: |
|||
|
|||
- [ ] 所有文件命名空间已更新 |
|||
- [ ] 所有 using 语句已更新 |
|||
- [ ] 项目文件已更新 |
|||
- [ ] 解决方案文件已更新 |
|||
- [ ] 代码编译无错误 |
|||
- [ ] 应用程序可以正常启动 |
|||
- [ ] 主要功能正常工作 |
|||
- [ ] 已更新 modify.md 记录修改 |
|||
|
|||
--- |
|||
|
|||
## 📝 修改记录 |
|||
|
|||
每次完成一个重要步骤后,请在 `modify.md` 文件中记录: |
|||
- 修改日期 |
|||
- 修改内容 |
|||
- 修改的文件列表 |
|||
- 遇到的问题及解决方案 |
|||
|
|||
--- |
|||
|
|||
**文档创建日期**: 2025年1月 |
|||
**最后更新**: 2025年1月 |
|||
**状态**: 计划阶段 |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue