在一些特殊情况下使用服务工厂而不是服务配置器是更好的决定:
1) 为旧的 PHP 类创建服务定义,因为在过去,创建逻辑通常隐藏在静态工厂类中
例如,Doctrine_Core::getTable()
public static function getTable($componentName)
{
return Doctrine_Manager::getInstance()->getConnectionForComponent($componentName)->getTable($componentName);
}
https://github.com/doctrine/doctrine1/blob/master/lib/Doctrine/Core.php
2) 使用工厂服务和检索服务的方法的一个特别好的例子是
以 Doctrine 存储库为例。当你需要一个时,你通常会注入一个实体管理器作为
构造函数参数,然后检索特定存储库:
use Doctrine\ORM\EntityManager;
class SomeClass
{
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function doSomething()
{
$repository = $this->entityManager->getRepository('User');
}
}
但是使用工厂服务和方法,您可以直接注入正确的存储库本身:
class SomeClass
{
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
}
...
<service id="some_service" class="SomeClass">
<argument type="user_repository" />
</service>
...
<service id="user_repository" class="UserRepository"
factory-service="entity_manager" factory-method="getRepository">
<argument>User</argument>
</service>
通过查看 SomeClass 的构造函数参数,很明显它需要一个
用户存储库,它比前面的示例更具体,更具交流性
SomeClass 需要一个 EntityManager 。除了使类本身更清洁之外,它还将使
当您为此编写单元测试时,为存储库创建一个替代对象要容易得多
班级。无需为实体管理器和存储库创建模拟,您只需
为存储库本身创建一个。
使用服务工厂的缺点是(根据 Matthias):
我反对使用静态工厂方法的工厂类是
静态代码是全局代码,执行该代码可能有副作用
无法隔离的效果(例如在测试场景中)。
此外,这种静态工厂方法的任何依赖都必须通过
定义静态本身,这也非常不利于隔离和
防止您自己替换(部分)创建逻辑
代码。工厂对象(或工厂服务)稍好一些。
然而,对它们的需求很可能指向某种设计
问题。服务不应该需要工厂,因为它将被创建
仅以预先确定的(和确定的)方式进行一次,从那时起
可以被任何其他对象完全重用。唯一的事情是
关于服务的动态,应该是方法的参数
是其公共接口的一部分