# SOLID 设计原则重构指南

## 🎯 重构目标

使用SOLID设计原则优化media_manager.py，提高代码的可维护性、可扩展性和可测试性。

## 📋 SOLID 原则应用

### 1. 单一职责原则 (SRP - Single Responsibility Principle)

#### 重构前问题
- `MediaManager`类承担了太多职责：依赖管理、视频信息提取、场景检测、文件管理等

#### 重构后改进
```python
# 依赖管理器 - 只负责管理依赖
class DependencyManager:
    def __init__(self):
        self._dependencies = {}
        self._initialize_dependencies()

# 视频信息提取器 - 只负责提取视频信息
class FFProbeVideoInfoExtractor(VideoInfoExtractor):
    def extract_video_info(self, file_path: str) -> Dict:
        # 专门负责使用ffprobe提取视频信息

# 场景检测器 - 只负责场景检测
class PySceneDetectSceneDetector(SceneDetector):
    def detect_scenes(self, file_path: str, threshold: float) -> List[float]:
        # 专门负责使用PySceneDetect检测场景

# 工厂类 - 只负责创建对象
class VideoProcessorFactory:
    def create_video_info_extractor(self) -> VideoInfoExtractor:
        # 专门负责创建合适的提取器
```

### 2. 开闭原则 (OCP - Open/Closed Principle)

#### 重构前问题
- 添加新的视频处理方法需要修改现有代码

#### 重构后改进
```python
# 抽象接口 - 对扩展开放，对修改关闭
class VideoInfoExtractor(ABC):
    @abstractmethod
    def extract_video_info(self, file_path: str) -> Dict:
        pass

class SceneDetector(ABC):
    @abstractmethod
    def detect_scenes(self, file_path: str, threshold: float) -> List[float]:
        pass

# 新的实现可以轻松添加，无需修改现有代码
class NewVideoInfoExtractor(VideoInfoExtractor):
    def extract_video_info(self, file_path: str) -> Dict:
        # 新的实现方法
        pass
```

### 3. 里氏替换原则 (LSP - Liskov Substitution Principle)

#### 重构后实现
```python
# 任何VideoInfoExtractor的子类都可以替换基类
def process_video(extractor: VideoInfoExtractor, file_path: str):
    info = extractor.extract_video_info(file_path)  # 可以是任何实现
    return info

# FFProbe实现
ffprobe_extractor = FFProbeVideoInfoExtractor()
info1 = process_video(ffprobe_extractor, "video.mp4")

# OpenCV实现
opencv_extractor = OpenCVVideoInfoExtractor(dependency_manager)
info2 = process_video(opencv_extractor, "video.mp4")
```

### 4. 接口隔离原则 (ISP - Interface Segregation Principle)

#### 重构前问题
- 大而全的接口，客户端被迫依赖不需要的方法

#### 重构后改进
```python
# 专门的接口，客户端只依赖需要的功能
class VideoInfoExtractor(ABC):
    @abstractmethod
    def extract_video_info(self, file_path: str) -> Dict:
        pass

class SceneDetector(ABC):
    @abstractmethod
    def detect_scenes(self, file_path: str, threshold: float) -> List[float]:
        pass

class VideoProcessor(ABC):
    @abstractmethod
    def split_video(self, input_path: str, output_dir: str, scene_times: List[float]) -> List[str]:
        pass
```

### 5. 依赖倒置原则 (DIP - Dependency Inversion Principle)

#### 重构前问题
- 高层模块直接依赖低层模块的具体实现

#### 重构后改进
```python
class MediaManager:
    def __init__(self, 
                 dependency_manager: DependencyManager = None,
                 video_info_extractor: VideoInfoExtractor = None,
                 scene_detector: SceneDetector = None):
        # 依赖注入 - 依赖抽象而不是具体实现
        self.dependency_manager = dependency_manager or globals()['dependency_manager']
        self.factory = VideoProcessorFactory(self.dependency_manager)
        
        # 延迟初始化处理器
        self._video_info_extractor = video_info_extractor
        self._scene_detector = scene_detector
    
    @property
    def video_info_extractor(self) -> VideoInfoExtractor:
        """懒加载 - 依赖抽象接口"""
        if self._video_info_extractor is None:
            self._video_info_extractor = self.factory.create_video_info_extractor()
        return self._video_info_extractor
```

## 🏗️ 重构架构

### 新的类层次结构

```
DependencyManager (依赖管理)
├── 检查和管理所有外部依赖
└── 提供统一的依赖访问接口

VideoInfoExtractor (抽象接口)
├── FFProbeVideoInfoExtractor (ffprobe实现)
└── OpenCVVideoInfoExtractor (OpenCV实现)

SceneDetector (抽象接口)
├── PySceneDetectSceneDetector (PySceneDetect实现)
└── OpenCVSceneDetector (OpenCV实现)

VideoProcessorFactory (工厂类)
├── 创建VideoInfoExtractor实例
└── 创建SceneDetector实例

MediaManager (协调器)
├── 使用依赖注入
├── 通过工厂创建处理器
└── 协调各个组件工作
```

## 🔧 使用示例

### 1. 基本使用 (使用默认实现)
```python
# 自动选择最佳实现
media_manager = MediaManager()
video_info = media_manager._get_video_info("video.mp4")
scene_changes = media_manager._detect_scene_changes("video.mp4")
```

### 2. 依赖注入使用
```python
# 手动指定实现
dependency_manager = DependencyManager()
video_extractor = FFProbeVideoInfoExtractor()
scene_detector = PySceneDetectSceneDetector(dependency_manager)

media_manager = MediaManager(
    dependency_manager=dependency_manager,
    video_info_extractor=video_extractor,
    scene_detector=scene_detector
)
```

### 3. 测试友好
```python
# 轻松进行单元测试
class MockVideoInfoExtractor(VideoInfoExtractor):
    def extract_video_info(self, file_path: str) -> Dict:
        return {"duration": 10.0, "width": 1920, "height": 1080}

# 注入Mock对象进行测试
mock_extractor = MockVideoInfoExtractor()
media_manager = MediaManager(video_info_extractor=mock_extractor)
```

## 📈 重构收益

### 1. 可维护性提升
- ✅ **单一职责**: 每个类只负责一个功能，易于理解和修改
- ✅ **代码解耦**: 组件之间松耦合，修改一个不影响其他
- ✅ **清晰架构**: 层次分明，职责明确

### 2. 可扩展性提升
- ✅ **新实现**: 轻松添加新的视频处理方法
- ✅ **插件化**: 支持插件式扩展
- ✅ **配置化**: 可以通过配置选择不同实现

### 3. 可测试性提升
- ✅ **依赖注入**: 轻松注入Mock对象
- ✅ **接口隔离**: 可以独立测试每个组件
- ✅ **单元测试**: 每个类都可以独立测试

### 4. 代码质量提升
- ✅ **类型安全**: 使用抽象基类和类型注解
- ✅ **错误处理**: 统一的错误处理机制
- ✅ **日志记录**: 详细的日志记录

## 🚀 迁移指南

### 1. 向后兼容
```python
# 保持向后兼容的全局变量
VIDEO_LIBS_AVAILABLE = dependency_manager.is_available('opencv')
SCENEDETECT_AVAILABLE = dependency_manager.is_available('scenedetect')

# 现有代码无需修改
media_manager = MediaManager()  # 仍然可以正常工作
```

### 2. 渐进式迁移
1. **第一阶段**: 使用新的MediaManager，保持现有接口
2. **第二阶段**: 逐步使用依赖注入
3. **第三阶段**: 完全迁移到新架构

### 3. 性能优化
- **懒加载**: 处理器只在需要时创建
- **缓存**: 依赖管理器缓存检查结果
- **工厂模式**: 统一的对象创建逻辑

## 🎯 最佳实践

### 1. 依赖管理
```python
# 统一的依赖检查
if dependency_manager.is_available('scenedetect'):
    # 使用PySceneDetect
else:
    # 回退到OpenCV
```

### 2. 错误处理
```python
# 统一的错误处理模式
try:
    return self.video_info_extractor.extract_video_info(file_path)
except Exception as e:
    logger.error(f"Failed to get video info: {e}")
    return default_video_info()
```

### 3. 扩展新功能
```python
# 添加新的视频处理器
class NewVideoProcessor(VideoProcessor):
    def split_video(self, input_path: str, output_dir: str, scene_times: List[float]) -> List[str]:
        # 新的实现
        pass

# 在工厂中注册
class VideoProcessorFactory:
    def create_video_processor(self) -> VideoProcessor:
        if self.dependency_manager.is_available('new_library'):
            return NewVideoProcessor()
        else:
            return DefaultVideoProcessor()
```

---

*通过SOLID原则重构，代码变得更加模块化、可测试和可维护！*
