基础的一 shot 意式浓缩,加不同的东西就成了不同的 [咖啡](咖啡.md) <!-- more --> ## 场景 基础的一 shot 意式浓缩,加不同的东西就成了不同的咖啡,基酒也是如此。 | | 意式浓缩 | 水 | 牛奶 | 奶油 | 巧克力 | | ---- | ---- | --- | --- | --- | --- | | 美式 | ✔️ | ✔️ | | | | | 摩卡 | ✔️ | | ✔️ | ✔️ | ✔️ | | 拿铁 | ✔️ | | ✔️ | | | | 卡布奇诺 | ✔️ | | ✔️ | ✔️ | | ## 实现 JavaIO 中基于基本的 inputstream 可以生成多种 file、object 等 stream ![image.png|1000](https://imagehosting4picgo.oss-cn-beijing.aliyuncs.com/imagehosting/fix-dir%2Fpicgo%2Fpicgo-clipboard-images%2F2024%2F05%2F10%2F11-45-09-e4dfc1a04daa6dd2f58409a9721bcb43-20240510114507-3dc3e2.png) ```python import os from contextlib import contextmanager from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy.pool import QueuePool from dotenv import load_dotenv class DatabaseManager: _instance = None # 用于实现单例模式 def __new__(cls): # 单例模式实现:确保只创建一个 DatabaseManager 实例 if cls._instance is None: cls._instance = super(DatabaseManager, cls).__new__(cls) cls._instance._initialize() return cls._instance def _initialize(self): # 初始化数据库连接 load_dotenv() # 加载 .env 文件中的环境变量 db_url = os.getenv('DATABASE_URL') if db_url is None: raise ValueError("DATABASE_URL not found in environment variables.") # 创建数据库引擎,配置连接池 self.engine = create_engine(db_url, poolclass=QueuePool, pool_size=5, max_overflow=10) # 创建线程安全的会话工厂 self.SessionFactory = scoped_session(sessionmaker(bind=self.engine)) @contextmanager def session_scope(self): # 上下文管理器,用于管理数据库会话 session = self.SessionFactory() try: yield session # 将会话提供给调用者 session.commit() # 如果没有异常,提交事务 except: session.rollback() # 如果有异常,回滚事务 raise finally: session.close() # 无论如何,确保关闭会话 # 创建 DatabaseManager 的全局实例 db_manager = DatabaseManager() ``` 您的观察非常敏锐。这个 `session_scope` 方法确实体现了一种类似于面向切面编程(Aspect-Oriented Programming, AOP)的思想。让我详细解释一下: 1. 切面编程的本质: AOP 的核心思想是将横切关注点(cross-cutting concerns)从主要业务逻辑中分离出来。在这个例子中,数据库会话的管理就是一个典型的横切关注点。 2. `session_scope` 作为切面: - 它封装了会话创建、提交、回滚和关闭的逻辑。 - 这些操作对于任何使用数据库的代码都是通用的,但不直接关联于特定的业务逻辑。 3. 装饰器模式: `@contextmanager` 装饰器使得 `session_scope` 成为一个生成器函数,可以用作上下文管理器。这种模式允许在进入和退出某个代码块时自动执行特定的操作。 4. 关注点分离: - 主要业务逻辑(在 `with` 块内的代码)不需要关心会话的生命周期管理。 - 会话管理的细节被封装在 `session_scope` 中,实现了关注点的分离。 5. 横切性质: 这种方法可以应用于任何需要数据库会话的操作,不限于特定的业务功能,体现了横切性质。 6. 一致性和可重用性: 通过这种方式,可以确保所有数据库操作都遵循相同的会话管理模式,提高了代码的一致性和可重用性。 让我们通过一个例子来进一步说明这种 AOP 思想: ```python # 使用 session_scope 的示例 class UserService: def create_user(self, username, email): with db_manager.session_scope() as session: new_user = User(username=username, email=email) session.add(new_user) # 会话管理由 session_scope 处理,而不是在这里显式地管理 def get_user(self, user_id): with db_manager.session_scope() as session: return session.query(User).filter(User.id == user_id).first() # 同样,会话的提交或回滚由 session_scope 处理 # 在这个例子中,UserService 的方法只关注业务逻辑 # 会话的生命周期管理被 "切面" (session_scope) 处理 ``` 在这个例子中: 1. 业务逻辑(创建用户、获取用户)与会话管理完全分离。 2. `session_scope` 作为一个 "切面",横跨所有需要数据库操作的方法。 3. 开发者可以专注于编写业务逻辑,而不必重复编写会话管理代码。 这种方法的优势包括: - 代码复用:会话管理逻辑只需要在一个地方定义。 - 一致性:所有数据库操作都以相同的方式处理会话。 - 可维护性:如果需要更改会话管理逻辑,只需要修改 `session_scope` 方法。 - 降低错误风险:自动化的会话管理减少了忘记提交或回滚事务的风险。 虽然 Python 没有像某些语言(如 Java 的 Spring AOP)那样的正式 AOP 框架,但这种使用上下文管理器的方法实现了类似的效果,体现了 AOP 的核心思想。 你对这种方法在实际项目中的应用有什么想法吗?或者你想了解如何将这种思想扩展到其他领域?