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

如何避免在实例化服务的方法中传递容器实例?

完全同意你的看法——直接传递容器属于服务定位器反模式,会让代码耦合度飙升,不仅难维护,测试起来也麻烦。这里有几个更干净的解决方案,帮你摆脱对容器的依赖:

方案1:注入专门的工厂类

既然你需要创建多个B类的实例,最符合单一职责原则的做法是定义一个专门的工厂类,负责封装B的创建逻辑。然后把这个工厂注入到A类中,而不是传递整个容器。

首先定义工厂类:

class BFactory {
    // 如果B类有依赖,直接注入到工厂的构造函数里即可
    public function __construct(/* B的依赖,比如 SomeDependency $dep */) {
        // 初始化依赖
    }

    public function create(): B {
        // 这里封装B的实例化逻辑
        return new B(/* 传入依赖 */);
    }
}

然后修改A类,通过构造函数注入工厂:

class A {
    private $bFactory;

    public function __construct(BFactory $bFactory) {
        $this->bFactory = $bFactory;
    }

    public function createBs() {
        foreach ($x as $y) {
            $b = $this->bFactory->create();
            // 对b执行操作
        }
    }
}

这样A类只依赖BFactory,而不是整个容器,职责更清晰。测试时你还可以轻松mock工厂类,返回自定义的B实例,方便单元测试。

方案2:注入创建B的回调函数

如果不想额外创建工厂类,你可以利用容器的回调注册功能(大部分PSR-11兼容的容器都支持),把创建B的逻辑封装成一个可调用对象,直接注入到A类中。

以Symfony容器为例,注册服务时可以这么写:

// 注册B类
$container->register(B::class);

// 注册A类,注入一个能创建B的回调
$container->register(A::class)
    ->addArgument(function (ContainerInterface $c) {
        return $c->get(B::class);
    });

然后修改A类接收这个回调:

class A {
    private $bCreator;

    public function __construct(callable $bCreator) {
        $this->bCreator = $bCreator;
    }

    public function createBs() {
        foreach ($x as $y) {
            $b = ($this->bCreator)();
            // 对b执行操作
        }
    }
}

这个方案省去了工厂类的定义,同时也避免了直接传递容器,A类只依赖一个简单的可调用对象,耦合度很低。

方案3:复用B的实例(仅限无状态场景)

如果B类是无状态的(即实例的属性不会在操作中被修改,或者每次操作前可以重置状态),那你甚至不需要每次创建新实例,直接注入一个B的实例到A类中循环复用即可。

class A {
    private $b;

    public function __construct(B $b) {
        $this->b = $b;
    }

    public function createBs() {
        foreach ($x as $y) {
            // 复用同一个B实例执行操作
            // 注意:如果B有状态,务必在每次循环前重置状态,避免数据污染
            $this->b->reset(); // 假设有重置状态的方法
            // 执行相关操作
        }
    }
}

这个方案最简单,但只适用于无状态的B类,否则会出现状态混乱的问题。

内容的提问来源于stack exchange,提问作者bartolaus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:02:33