# 数字人任务策略模式优化 ## 概述 本次重构将数字人任务的口型同步逻辑从传统的 if-else 条件判断优化为**策略模式**,提升了代码的可维护性、可扩展性和可测试性。 ## 架构设计 ### 1. 策略模式结构 ``` ┌─────────────────────────────────────────┐ │ DigitalHumanTaskServiceImpl │ │ - syncLip() │ │ ├─ lipSyncStrategyFactory │ │ └─ getStrategyForTask() │ └───────────────┬─────────────────────────┘ │ ▼ ┌───────────────────┐ │ LipSyncStrategy │ (接口) │ + syncLip() │ │ + getStrategyName()│ │ + supports() │ │ + getPriority() │ │ + getDescription()│ └────────┬──────────┘ │ ├────────────────────┬────────────────────── │ │ ▼ ▼ ┌──────────────┐ ┌──────────────────────┐ │KlingStrategy │ │LatentsyncStrategy │ │ - Priority: │ │ - Priority: 50 │ │ 100 │ │ - Fallback策略 │ │ - Advanced │ │ - 通用口型同步 │ │ Lip-Sync │ └──────────────────────┘ └──────────────┘ ``` ### 2. 核心组件 #### 2.1 LipSyncStrategy 接口 ```java public interface LipSyncStrategy { // 执行口型同步 String syncLip(TikDigitalHumanTaskDO task, String audioUrl) throws Exception; // 策略名称 String getStrategyName(); // 是否支持该任务 boolean supports(TikDigitalHumanTaskDO task); // 优先级(数字越大优先级越高) int getPriority(); // 策略描述 String getDescription(); } ``` #### 2.2 LipSyncStrategyFactory 工厂类 ```java @Component public class LipSyncStrategyFactory { // 注册策略 public void registerStrategy(LipSyncStrategy strategy); // 根据任务选择策略 public LipSyncStrategy getStrategyForTask(TikDigitalHumanTaskDO task); // 获取所有支持的策略 public List getAllStrategies(); } ``` #### 2.3 具体策略实现 **KlingLipSyncStrategy(优先级 100)** - 使用可灵 advanced-lip-sync API - 要求:`klingSessionId` 和 `klingFaceId` - 如果参数缺失,自动回退到 Latentsync **LatentsyncLipSyncStrategy(优先级 50)** - 使用 302.ai Latentsync 通用接口 - 作为默认回退策略 - 支持所有标准的口型同步任务 ### 3. 工作流程 ``` 1. 创建任务 → 验证参数 → 存储记录 │ ▼ 2. 异步处理 → prepareFiles → synthesizeVoice │ ▼ 3. 选择策略 → getStrategyForTask() │ ├─ Kling策略(如果支持) └─ Latentsync策略(回退) │ ▼ 4. 执行口型同步 → 提交异步任务 → 加入轮询队列 │ ▼ 5. 轮询服务检测状态 → 更新任务 → 返回结果 ``` ## 重构详情 ### 修改前的问题 **问题 1:违反开闭原则** ```java // 传统 if-else 实现 if ("302ai".equals(aiProvider)) { syncWithLatentsync(); } else if ("kling".equals(aiProvider)) { syncWithKling(); } else if ("aliyun".equals(aiProvider)) { // TODO: 新增供应商需要修改此方法 } ``` **问题 2:职责不单一** - 每个分支包含大量业务逻辑 - 难以单元测试 - 重复代码多 **问题 3:可扩展性差** - 新增 AI 供应商需要修改核心服务类 - 违反单一职责原则 ### 修改后的优势 **优势 1:符合开闭原则** ```java // 新增供应商只需: 1. 创建新的策略实现类 2. 使用 @Component 注解自动注册 3. 无需修改 DigitalHumanTaskServiceImpl ``` **优势 2:职责分离** ```java // 每个策略类专注自己的业务逻辑 KlingLipSyncStrategy → 专注可灵接口 LatentsyncLipSyncStrategy → 专注 Latentsync 接口 DigitalHumanTaskServiceImpl → 专注任务流程编排 ``` **优势 3:可测试性强** ```java // 可以独立测试每个策略 @Test public void testKlingStrategy() { // 测试可灵策略逻辑 } @Test public void testLatentsyncStrategy() { // 测试 Latentsync 策略逻辑 } ``` ## 新增文件 ### 1. 策略接口 - `cn.iocoder.yudao.module.tik.voice.strategy.LipSyncStrategy.java` ### 2. 策略工厂 - `cn.iocoder.yudao.module.tik.voice.strategy.LipSyncStrategyFactory.java` ### 3. 具体策略 - `cn.iocoder.yudao.module.tik.voice.strategy.impl.KlingLipSyncStrategy.java` - `cn.iocoder.yudao.module.tik.voice.strategy.impl.LatentsyncLipSyncStrategy.java` ## 修改文件 ### 1. DigitalHumanTaskServiceImpl.java - ✅ 移除 `syncWithLatentsync()` 方法 - ✅ 移除 `syncWithKling()` 方法 - ✅ 重构 `syncLip()` 方法使用策略模式 - ✅ 注入 `LipSyncStrategyFactory` 和 `KlingService` ## 策略选择逻辑 ```java public LipSyncStrategy getStrategyForTask(TikDigitalHumanTaskDO task) { // 1. 获取所有支持的策略 List supportedStrategies = strategies.stream() .filter(strategy -> strategy.supports(task)) .collect(Collectors.toList()); // 2. 按优先级排序 supportedStrategies.sort((a, b) -> b.getPriority() - a.getPriority()); // 3. 返回最高优先级的策略 return supportedStrategies.isEmpty() ? null : supportedStrategies.get(0); } ``` ## 扩展指南 ### 新增 AI 供应商(例如:阿里云) **步骤 1:创建策略类** ```java @Component public class AliyunLipSyncStrategy implements LipSyncStrategy { @Override public String syncLip(TikDigitalHumanTaskDO task, String audioUrl) { // 1. 构建阿里云请求参数 // 2. 调用阿里云 API // 3. 加入轮询队列 } @Override public String getStrategyName() { return "aliyun"; } @Override public boolean supports(TikDigitalHumanTaskDO task) { return "aliyun".equalsIgnoreCase(task.getAiProvider()); } @Override public int getPriority() { return 75; // 可灵之下,Latentsync 之上 } @Override public String getDescription() { return "阿里云语音驱动视频服务"; } } ``` **步骤 2:无需修改其他代码** - 策略工厂会自动注册 - 任务处理时会自动选择 ## 回退机制 当高优先级策略因参数缺失无法执行时,会自动回退到低优先级策略: ``` Kling任务 → KlingStrategy检查参数 ├─ 参数完整 → 使用 Kling advanced-lip-sync └─ 参数缺失 → 返回false,尝试Latentsync策略 └─ LatentsyncStrategy → 支持 → 使用通用接口 ``` ## 性能优化 1. **策略缓存**:工厂类使用 `@Cacheable` 缓存策略选择结果 2. **延迟加载**:策略按需创建和初始化 3. **优先级排序**:一次性排序,避免重复计算 ## 测试建议 ### 单元测试 ```java @Test public void testKlingStrategySupports() { // 测试支持条件 } @Test public void testKlingStrategySync() { // 测试口型同步逻辑 } @Test public void testLatentsyncStrategySupports() { // 测试回退逻辑 } @Test public void testStrategyFactory() { // 测试策略选择逻辑 } ``` ### 集成测试 ```java @Test public void testEndToEndWithKling() { // 测试完整的可灵流程 } @Test public void testEndToEndWithLatentsync() { // 测试完整的 Latentsync 流程 } ``` ## 总结 通过策略模式的引入,我们实现了: ✅ **高内聚低耦合** - 每个策略专注自己的业务 ✅ **易于扩展** - 新增供应商无需修改核心代码 ✅ **易于维护** - 策略之间相互独立,修改互不影响 ✅ **易于测试** - 每个策略可以独立单元测试 ✅ **代码复用** - 移除重复代码,统一处理流程 这套架构设计遵循了 SOLID 原则,特别是: - **单一职责原则(SRP)**:每个策略只负责一种 AI 供应商 - **开放封闭原则(OCP)**:对扩展开放,对修改封闭 - **依赖倒置原则(DIP)**:依赖抽象而非具体实现