This commit is contained in:
root
2025-07-11 19:52:04 +08:00
parent 82c1c71771
commit 4791a50955
6 changed files with 1543 additions and 139 deletions

View File

@@ -0,0 +1,280 @@
# 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原则重构代码变得更加模块化、可测试和可维护*