我是Symfony2的新手,有点困惑。对不起,如果这个问题听起来很傻。
creating service with factory和 Tagged Services 都用于假设创建工厂。
根据上述链接中的文档,我能想出的差异是:
对于标记服务:
您需要编写编译器传递,然后为每个服务定义一个标记。
然后写一个工厂(任何类。这应该被称为工厂吗?),它将从编译器传递中获取所有标记服务的对象。另外在这里创建一个getter方法,它将根据一些标准返回对象。
如果使用工厂创建服务,您只能创建一个服务,并通过调用静态方法将其对象返回给您。
所以,我想,在标记服务中,您可以从众多服务中进行选择,并且在创建逐个服务的情况下,您只能创建单个服务。我认为标记服务已经服务于工厂的目的。为什么我们只能在创建单个对象时才需要工厂服务?可能我在这里有一个误解,但标记服务更好,因为编译器传递是在缓存预热上运行的,标记服务本身存储在那里,所以它会更快。但是,服务也被缓存,因此应该没有太大的区别。但我不确定这种概念化是否正确。
请让我理解两者的概念,让我感到开悟。
答案 0 :(得分:9)
工厂服务和标记服务具有完全不同的角色。我将尝试通过示例向您说明一些常见情况,当您可能想要使用其中一种情况时。
当服务容器中没有构建服务所需的某些参数时,或者在实例化服务之前需要进行一些准备工作时,通常会使用它。 Symfony会自动检查您的服务是否拥有自己的工厂,或者直接从容器参数构建。
您有一项处理PayPal付款的服务。要构建它,您需要在PayPal凭据和API端点URL中传递它。
class PayPalPaymentService
{
// ...
public function __construct(PayPalCredentials $credentials, $apiEndpoint)
{
// ...
}
// ...
}
这适合您,但您意识到您需要有两种环境:直播和沙盒。您的凭据和API端点URL都会有所不同,具体取决于您所处的环境。
Symfony有几种方法可以为您处理,但其中一种方法是通过工厂服务:您创建一个工厂,根据您当前的情况实例化 PayPalPaymentService 当地环境。
class PayPalPaymentServiceFactory
{
const SANDBOX_ENDPOINT = '...';
const LIVE_ENDPOINT = '...';
private $livePublic;
// ...
public function __construct($livePublic, $liveSecret, $sandboxPublic, $sandboxSecret, $kernelEnvironment)
{
$this->livePublic = $livePublic;
// ...
}
public function create()
{
if ('prod' === $kernelEnvironment) {
$credentials = new PayPalCredentials($this->livePublic, $this->liveSecret);
} else {
$credentials = new PayPalCredentials($this->sandboxPublic, $this->sandboxSecret);
}
$url = 'prod' === $kernelEnvironment ? self::LIVE_ENDPOINT : self::SANDBOX_ENDPOINT;
return new PayPalPaymentService($credentials, $url);
}
}
现在,每当您注入PayPalPaymentService时,容器将首先要求您的PayPalPaymentServiceFactory创建它,然后注入它。
这些完全是另一回事。在整个Symfony代码库中使用标记服务:用于FormTypes,Twig Extensions,Validator等。标记服务的概念是一种非常强大的扩展机制。它允许您将标记您的服务视为用于特定目的的内容。正如我所说,在Symfony代码库中已经有它们的例子,但是这里有一个非常简单的例子来看看你能用它们做些什么:
您的电子商店有付款,并且您有支持的付款处理器列表。每个支付处理器都有自己的结账页面。因此,您决定将其模块化,让其他人为其创建新的支付处理器。
在您的购物车页面上,您需要显示指向所有可用付款处理器结帐页面的链接,为此,您有一项服务可以为您提供所有可用的结帐链接:
class CheckoutLinksProvider
{
/**
* @var ProcessorAdapter[]
*/
private $adapters;
public function registerProcessor(ProcessorAdapter $adapter)
{
$this->adapters = $adapter;
}
public function getCheckoutLinks()
{
$links = [];
foreach ($this->adapters as $adapter) {
$links[] = $adapter->getCheckoutLink();
}
return $links;
}
}
interface ProcessorAdapter
{
/**
* @return string Checkout URL link
*/
public function getCheckoutLink();
// ...
}
现在,任何人都可以实现ProcessorAdapter
并在Github上将其作为捆绑包共享!他们所要做的只是使用您决定的某个标记标记其ProcessorAdapter
实施,例如:' my_eshop_processor_adapter'。
在您的核心电子商店系统编译器通过中,您现在可以选择所有ProcessorAdapter
实施并在CheckoutLinksProvider
服务中注册它们。瞧!您已经拥有完全模块化的支付系统!任何人都可以创建对自定义处理器的支持,您只需下载它们的包并在内核中注册它们,就会出现结帐链接!