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