You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 22:32:28