Python新手求助:不使用DI库在Command Pattern中注入Repository类的实现方案
不依赖DI库的Python命令模式依赖注入方案
作为有Java背景的开发者,我太懂你想摆脱硬依赖、实现解耦的心情了!在Python里不用第三方DI库也能轻松实现依赖注入,而且方案足够简洁,完全符合你的需求。咱们一步步来调整你的代码:
核心思路:构造函数注入(按需传递)
最直接也最符合Python风格的方式就是构造函数注入——把Database实例作为参数传给需要它的Command子类,基类只负责接收和存储,不再硬初始化。这样不需要数据库的命令就不用传这个参数,完美避免冗余。
修改后的代码实现
1. 调整基类 Command(command.py)
from abc import ABC, abstractmethod from report.repository.database import Database class Command(ABC): def __init__(self, repository: Database = None) -> None: self.repository = repository # 由外部传入,不再硬编码初始化 @abstractmethod def execute(self): pass
这里给repository加了默认值None,目的是让不需要数据库的命令子类可以不用传递这个参数,保持灵活性。
2. 调整需要数据库的子类 AddDriver(add_driver.py)
from report.parser.command import Command class AddDriver(Command): def __init__(self, name, repository: Database) -> None: super().__init__(repository) self.name = name def execute(self): # 可选:如果想更严谨,可以加个检查确保repository不为空 if not self.repository: raise ValueError("AddDriver command requires a Database instance") self.repository.add_driver(self.name)
这里我们明确要求AddDriver的构造函数必须传入repository,因为这个命令确实需要数据库操作——这样依赖关系一目了然,也避免了运行时出错。
3. 使用时注入共享的Database实例
在创建命令对象的时候,先初始化一个共享的Database实例,然后传给需要它的命令:
from report.repository.database import Database from report.parser.add_driver import AddDriver # 初始化全局/共享的数据库实例(可以根据需求放在合适的地方,比如配置模块) shared_db = Database() # 创建AddDriver命令时,注入共享的数据库实例 add_john_cmd = AddDriver("John Doe", shared_db) add_john_cmd.execute() # 后续生成报告的命令也可以复用这个shared_db实例 # generate_report_cmd = GenerateReport(shared_db) # generate_report_cmd.execute()
进阶优化:用工厂模式简化注入(可选)
如果你的命令很多,每次创建都手动传shared_db会有点繁琐,这时可以用命令工厂来统一管理依赖:
from report.repository.database import Database from report.parser.add_driver import AddDriver class CommandFactory: def __init__(self, db: Database): self.shared_db = db def create_add_driver(self, name): return AddDriver(name, self.shared_db) # 后续新增命令时,只需要在这里加对应的创建方法 # def create_generate_report(self): # return GenerateReport(self.shared_db) # 使用工厂 factory = CommandFactory(shared_db) add_jane_cmd = factory.create_add_driver("Jane Smith") add_jane_cmd.execute()
工厂模式不仅能简化命令的创建,还能让依赖管理更集中,以后要替换数据库实现(比如测试时用Mock数据库),只需要修改工厂初始化的地方就行。
为什么这个方案适合你?
- 无第三方依赖:完全不用引入Guice之类的DI库,保持代码轻量简洁
- 按需注入:不需要数据库的命令(比如纯内存计算的命令)可以不用传
repository参数,避免冗余 - 解耦彻底:
Command类不再和Database硬绑定,以后替换数据库实现(比如换成SQLite/MySQL的封装类),只需要传入不同的实例,不用修改命令本身的代码 - 符合Python风格:构造函数注入是Python中实现依赖注入最直观的方式,可读性强,新手也容易理解
内容的提问来源于stack exchange,提问作者toy
相关产品推荐
相关产品推荐

