# 模块化设计思想 ## 🎯 学习目标 通过本节学习,您将能够: - 理解模块化设计的核心思想和优势 - 掌握模块划分的原则和方法 - 学会设计清晰的模块接口 - 了解模块间通信的最佳实践 - 在Chat-Room项目中应用模块化设计 ## 📖 模块化设计概述 模块化设计是将复杂系统分解为相对独立、功能明确的模块的设计方法。每个模块负责特定的功能,模块间通过定义良好的接口进行交互。 ### 模块化设计的核心原则 ```mermaid graph TD A[模块化设计原则] --> B[单一职责原则] A --> C[开闭原则] A --> D[接口隔离原则] A --> E[依赖倒置原则] B --> B1[每个模块只做一件事] B --> B2[职责明确且集中] C --> C1[对扩展开放] C --> C2[对修改封闭] D --> D1[接口最小化] D --> D2[避免接口污染] E --> E1[依赖抽象而非具体] E --> E2[高层模块不依赖低层模块] style A fill:#e8f5e8 style B fill:#fff3cd style C fill:#f8d7da style D fill:#e1f5fe style E fill:#f3e5f5 ``` ## 🏗️ Chat-Room项目的模块化架构 ### 整体模块架构 ```mermaid graph TB subgraph "客户端模块" C1[UI模块
用户界面] C2[Core模块
核心逻辑] C3[Commands模块
命令处理] end subgraph "服务器模块" S1[Core模块
服务器核心] S2[Database模块
数据库操作] S3[AI模块
AI集成] S4[Utils模块
工具函数] end subgraph "共享模块" SH1[Messages模块
消息协议] SH2[Constants模块
常量定义] SH3[Exceptions模块
异常处理] SH4[Logger模块
日志系统] end C1 --> C2 C2 --> C3 C2 --> SH1 C3 --> SH2 S1 --> S2 S1 --> S3 S1 --> S4 S1 --> SH1 S2 --> SH3 S3 --> SH4 style C1 fill:#e8f5e8 style S1 fill:#fff3cd style SH1 fill:#f8d7da ``` ## 🔧 模块设计实践 ### 1. 消息协议模块设计 ```python """ 消息协议模块 - shared/messages.py 定义系统中所有消息类型和协议 """ from abc import ABC, abstractmethod from enum import Enum from typing import Dict, Any, Optional from dataclasses import dataclass import json import time class MessageType(Enum): """消息类型枚举""" # 认证相关 LOGIN = "login" LOGOUT = "logout" REGISTER = "register" # 聊天相关 CHAT = "chat" PRIVATE_CHAT = "private_chat" GROUP_CHAT = "group_chat" # 文件相关 FILE_UPLOAD = "file_upload" FILE_DOWNLOAD = "file_download" # 系统相关 SYSTEM = "system" ERROR = "error" HEARTBEAT = "heartbeat" @dataclass class BaseMessage(ABC): """消息基类 - 定义所有消息的通用接口""" message_id: str message_type: MessageType sender: Optional[str] = None timestamp: float = None def __post_init__(self): if self.timestamp is None: self.timestamp = time.time() @abstractmethod def to_dict(self) -> Dict[str, Any]: """转换为字典格式""" pass @abstractmethod def validate(self) -> bool: """验证消息格式""" pass def to_json(self) -> str: """转换为JSON字符串""" return json.dumps(self.to_dict(), ensure_ascii=False) @classmethod @abstractmethod def from_dict(cls, data: Dict[str, Any]) -> 'BaseMessage': """从字典创建消息对象""" pass @dataclass class ChatMessage(BaseMessage): """聊天消息""" content: str = "" target: Optional[str] = None # 私聊目标或群组ID def __post_init__(self): super().__post_init__() self.message_type = MessageType.CHAT def to_dict(self) -> Dict[str, Any]: return { "message_id": self.message_id, "type": self.message_type.value, "sender": self.sender, "content": self.content, "target": self.target, "timestamp": self.timestamp } def validate(self) -> bool: return bool( self.message_id and self.sender and self.content.strip() ) @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'ChatMessage': return cls( message_id=data["message_id"], sender=data.get("sender"), content=data.get("content", ""), target=data.get("target"), timestamp=data.get("timestamp") ) class MessageFactory: """消息工厂 - 负责创建和解析消息""" _message_classes = { MessageType.CHAT: ChatMessage, # 其他消息类型... } @classmethod def create_message(cls, message_type: MessageType, **kwargs) -> Optional[BaseMessage]: """创建消息对象""" message_class = cls._message_classes.get(message_type) if not message_class: return None try: message = message_class(**kwargs) return message if message.validate() else None except Exception: return None @classmethod def parse_message(cls, json_data: str) -> Optional[BaseMessage]: """解析JSON消息""" try: data = json.loads(json_data) message_type = MessageType(data.get("type")) message_class = cls._message_classes.get(message_type) if message_class: return message_class.from_dict(data) return None except Exception: return None ``` ### 2. 数据库模块设计 ```python """ 数据库模块 - server/database/operations.py 封装所有数据库操作,提供统一接口 """ from abc import ABC, abstractmethod from typing import List, Dict, Any, Optional import sqlite3 import threading class DatabaseInterface(ABC): """数据库接口 - 定义数据库操作的抽象接口""" @abstractmethod def connect(self) -> bool: """连接数据库""" pass @abstractmethod def disconnect(self) -> None: """断开数据库连接""" pass @abstractmethod def execute_query(self, query: str, params: tuple = ()) -> List[Dict[str, Any]]: """执行查询""" pass @abstractmethod def execute_update(self, query: str, params: tuple = ()) -> int: """执行更新""" pass class SQLiteDatabase(DatabaseInterface): """SQLite数据库实现""" def __init__(self, db_path: str): self.db_path = db_path self.connection: Optional[sqlite3.Connection] = None self._lock = threading.Lock() def connect(self) -> bool: """连接数据库""" try: self.connection = sqlite3.connect( self.db_path, check_same_thread=False ) self.connection.row_factory = sqlite3.Row return True except Exception: return False def disconnect(self) -> None: """断开数据库连接""" if self.connection: self.connection.close() self.connection = None def execute_query(self, query: str, params: tuple = ()) -> List[Dict[str, Any]]: """执行查询""" with self._lock: cursor = self.connection.cursor() cursor.execute(query, params) rows = cursor.fetchall() return [dict(row) for row in rows] def execute_update(self, query: str, params: tuple = ()) -> int: """执行更新""" with self._lock: cursor = self.connection.cursor() cursor.execute(query, params) self.connection.commit() return cursor.rowcount class UserRepository: """用户数据仓库 - 封装用户相关的数据库操作""" def __init__(self, database: DatabaseInterface): self.db = database def create_user(self, username: str, password_hash: str, email: str = None) -> bool: """创建用户""" query = """ INSERT INTO users (username, password_hash, email, created_at) VALUES (?, ?, ?, datetime('now')) """ try: rows_affected = self.db.execute_update(query, (username, password_hash, email)) return rows_affected > 0 except Exception: return False def get_user_by_username(self, username: str) -> Optional[Dict[str, Any]]: """根据用户名获取用户""" query = "SELECT * FROM users WHERE username = ?" results = self.db.execute_query(query, (username,)) return results[0] if results else None def update_user_status(self, user_id: int, status: str) -> bool: """更新用户状态""" query = "UPDATE users SET status = ?, last_active = datetime('now') WHERE id = ?" try: rows_affected = self.db.execute_update(query, (status, user_id)) return rows_affected > 0 except Exception: return False def get_online_users(self) -> List[Dict[str, Any]]: """获取在线用户列表""" query = "SELECT id, username FROM users WHERE status = 'online'" return self.db.execute_query(query) class ChatRepository: """聊天数据仓库 - 封装聊天相关的数据库操作""" def __init__(self, database: DatabaseInterface): self.db = database def save_message(self, sender_id: int, content: str, chat_type: str = "public", target_id: int = None) -> bool: """保存消息""" query = """ INSERT INTO messages (sender_id, content, chat_type, target_id, created_at) VALUES (?, ?, ?, ?, datetime('now')) """ try: rows_affected = self.db.execute_update( query, (sender_id, content, chat_type, target_id) ) return rows_affected > 0 except Exception: return False def get_recent_messages(self, limit: int = 50) -> List[Dict[str, Any]]: """获取最近的消息""" query = """ SELECT m.*, u.username as sender_name FROM messages m JOIN users u ON m.sender_id = u.id WHERE m.chat_type = 'public' ORDER BY m.created_at DESC LIMIT ? """ return self.db.execute_query(query, (limit,)) def get_private_messages(self, user1_id: int, user2_id: int, limit: int = 50) -> List[Dict[str, Any]]: """获取私聊消息""" query = """ SELECT m.*, u.username as sender_name FROM messages m JOIN users u ON m.sender_id = u.id WHERE m.chat_type = 'private' AND ((m.sender_id = ? AND m.target_id = ?) OR (m.sender_id = ? AND m.target_id = ?)) ORDER BY m.created_at DESC LIMIT ? """ return self.db.execute_query(query, (user1_id, user2_id, user2_id, user1_id, limit)) ``` ### 3. 用户管理模块设计 ```python """ 用户管理模块 - server/core/user_manager.py 负责用户相关的业务逻辑 """ import hashlib import secrets from typing import Dict, List, Optional from dataclasses import dataclass from enum import Enum class UserStatus(Enum): """用户状态枚举""" OFFLINE = "offline" ONLINE = "online" AWAY = "away" BUSY = "busy" @dataclass class User: """用户数据模型""" id: int username: str email: Optional[str] = None status: UserStatus = UserStatus.OFFLINE last_active: Optional[str] = None created_at: Optional[str] = None class UserManager: """用户管理器 - 封装用户相关的业务逻辑""" def __init__(self, user_repository, logger): self.user_repo = user_repository self.logger = logger self.active_sessions: Dict[str, User] = {} # session_id -> User def register_user(self, username: str, password: str, email: str = None) -> bool: """注册新用户""" # 验证输入 if not self._validate_username(username): self.logger.warning(f"无效的用户名: {username}") return False if not self._validate_password(password): self.logger.warning(f"密码不符合要求") return False # 检查用户名是否已存在 if self.user_repo.get_user_by_username(username): self.logger.warning(f"用户名已存在: {username}") return False # 创建用户 password_hash = self._hash_password(password) success = self.user_repo.create_user(username, password_hash, email) if success: self.logger.info(f"用户注册成功: {username}") else: self.logger.error(f"用户注册失败: {username}") return success def authenticate_user(self, username: str, password: str) -> Optional[str]: """用户认证,返回session_id""" user_data = self.user_repo.get_user_by_username(username) if not user_data: self.logger.warning(f"用户不存在: {username}") return None # 验证密码 if not self._verify_password(password, user_data["password_hash"]): self.logger.warning(f"密码错误: {username}") return None # 创建会话 session_id = self._generate_session_id() user = User( id=user_data["id"], username=user_data["username"], email=user_data.get("email"), status=UserStatus.ONLINE ) self.active_sessions[session_id] = user # 更新用户状态 self.user_repo.update_user_status(user.id, UserStatus.ONLINE.value) self.logger.info(f"用户登录成功: {username}") return session_id def logout_user(self, session_id: str) -> bool: """用户登出""" if session_id not in self.active_sessions: return False user = self.active_sessions[session_id] # 更新用户状态 self.user_repo.update_user_status(user.id, UserStatus.OFFLINE.value) # 移除会话 del self.active_sessions[session_id] self.logger.info(f"用户登出: {user.username}") return True def get_user_by_session(self, session_id: str) -> Optional[User]: """根据会话ID获取用户""" return self.active_sessions.get(session_id) def get_online_users(self) -> List[User]: """获取在线用户列表""" return list(self.active_sessions.values()) def _validate_username(self, username: str) -> bool: """验证用户名""" return ( len(username) >= 3 and len(username) <= 20 and username.isalnum() ) def _validate_password(self, password: str) -> bool: """验证密码""" return len(password) >= 6 def _hash_password(self, password: str) -> str: """密码哈希""" salt = secrets.token_hex(16) password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000) return f"{salt}:{password_hash.hex()}" def _verify_password(self, password: str, stored_hash: str) -> bool: """验证密码""" try: salt, hash_hex = stored_hash.split(':') password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000) return password_hash.hex() == hash_hex except Exception: return False def _generate_session_id(self) -> str: """生成会话ID""" return secrets.token_urlsafe(32) ``` ## 🔗 模块间通信 ### 1. 事件驱动通信 ```python """ 事件驱动的模块间通信 """ from typing import Callable, Dict, List from enum import Enum class EventType(Enum): USER_LOGIN = "user_login" USER_LOGOUT = "user_logout" MESSAGE_SENT = "message_sent" FILE_UPLOADED = "file_uploaded" class EventBus: """事件总线 - 模块间通信的中介""" def __init__(self): self._subscribers: Dict[EventType, List[Callable]] = {} def subscribe(self, event_type: EventType, callback: Callable) -> None: """订阅事件""" if event_type not in self._subscribers: self._subscribers[event_type] = [] self._subscribers[event_type].append(callback) def publish(self, event_type: EventType, data: dict) -> None: """发布事件""" if event_type in self._subscribers: for callback in self._subscribers[event_type]: try: callback(data) except Exception as e: print(f"事件处理错误: {e}") # 使用示例 event_bus = EventBus() # 用户管理器订阅登录事件 def on_user_login(data): print(f"用户 {data['username']} 登录了") event_bus.subscribe(EventType.USER_LOGIN, on_user_login) # 发布登录事件 event_bus.publish(EventType.USER_LOGIN, {"username": "test_user"}) ``` ## 📊 模块化设计的优势 ### 1. 可维护性 - **职责分离**:每个模块职责明确,易于理解和修改 - **影响范围小**:修改一个模块不会影响其他模块 - **测试简单**:可以独立测试每个模块 ### 2. 可扩展性 - **功能扩展**:可以轻松添加新模块 - **接口稳定**:模块接口稳定,内部实现可以改变 - **插件架构**:支持插件式的功能扩展 ### 3. 可重用性 - **模块复用**:模块可以在不同项目中重用 - **组合灵活**:可以灵活组合不同模块 - **标准化**:统一的接口标准 ## 📋 学习检查清单 完成本节学习后,请确认您能够: - [ ] 理解模块化设计的核心思想 - [ ] 掌握模块划分的原则和方法 - [ ] 设计清晰的模块接口 - [ ] 实现模块间的有效通信 - [ ] 在实际项目中应用模块化设计 ## 🚀 下一步 完成模块化设计学习后,请继续学习: - [包管理与依赖控制](../02-development-environment/package-management.md) - [配置管理最佳实践](configuration-management.md) --- ## 📖 导航 ⬅️ **上一节:** [Project Organization](project-organization.md) ➡️ **下一节:** [Pep8 Standards](pep8-standards.md) 📚 **返回:** [第4章:软件工程](README.md) 🏠 **主页:** [学习路径总览](../README.md) **模块化设计让代码更清晰、更易维护!** 🧩