Jak*_*e N 3 service factory-pattern symfony
我一直试图解决这个问题
http://symfony.com/doc/current/service_container/factories.html
但是似乎有一块缺失让所有人都厌倦了或者我完全忽略了这一点.
该示例具有工厂类
class NewsletterManagerFactory
{
public static function createNewsletterManager()
{
$newsletterManager = new NewsletterManager();
// ...
return $newsletterManager;
}
}
Run Code Online (Sandbox Code Playgroud)
然后通过服务将该工厂配置为工厂类和NewsletterManager服务方法.
services:
app.newsletter_manager_factory:
class: AppBundle\Email\NewsletterManagerFactory
app.newsletter_manager:
class: AppBundle\Email\NewsletterManager
factory: 'app.newsletter_manager_factory:createNewsletterManager'
Run Code Online (Sandbox Code Playgroud)
所以现在我们有一个通过param NewsletterManager知道NewsletterManagerFactoryClass的Classfactory:services.yml
题
你如何利用这种配置?现在暴露在内的NewsletterManager是什么让我可以createNewsletterManager在工厂上课?
据我所知,这两项服务仍然是完全分开的?
我曾经使用过这种模式.这是它的用例.
试想一下,你有多个窗口小部件类,即Acme\Widget1,Acme\Widget2,Acme\WidgetN.
每个小部件都有高级实例化过程,因此您决定使用工厂.它还具有复杂的依赖关系链,每个窗口小部件都需要实例化.即Acme\Dependency1,Acme\Dependency2,Acme\Dependency3.
所以你要做的就是创建Acme\WidgetFactory一次具有依赖关系的服务.然后,您需要Acme\WidgetFactory为每个小部件指定为工厂.如果窗口小部件实例化方式发生了某些变化,您只需要更改一个类和一个服务定义.所有1到N小部件服务保持不变.
这是一个例子......
典型的实施方式:
acme.widget1:
class: Acme\Widget1
factory: ['Acme\Widget1', 'create']
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widget2:
class: Acme\Widget2
factory: ['Acme\Widget2, 'create']
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widgetN:
class: Acme\WidgetN
factory: ['Acme\WidgetN', 'create']
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
Run Code Online (Sandbox Code Playgroud)
在这里你有强烈的代码重复气味.如果你想改变一些你需要做N次.
相反,这是你可以做的.
acme.widget_factory:
class: Acme\WidgetFactory
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widget1:
class: Acme\Widget1
factory: ['@acme.widget_factory', createWidget]
acme.widget2:
class: Acme\Widget2
factory: ['@acme.widget_factory', createWidget]
acme.widgetN:
class: Acme\WidgetN
factory: ['@acme.widget_factory', createWidget]
Run Code Online (Sandbox Code Playgroud)
代码重复已经消失.
出现了小小的不便......工厂不知道要实例化的具体类.我使用了以下技术.
我标记了每个小部件,然后在编译器传递期间向工厂添加了额外的参数.
acme.widget_factory:
class: Acme\WidgetFactory
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widget1:
class: Acme\Widget1
factory: ['@acme.widget_factory', createWidget]
tags:
- { name: acme.widget }
acme.widget2:
class: Acme\Widget2
factory: ['@acme.widget_factory', createWidget]
tags:
- { name: acme.widget }
acme.widgetN:
class: Acme\WidgetN
factory: ['@acme.widget_factory', createWidget]
tags:
- { name: acme.widget }
Run Code Online (Sandbox Code Playgroud)
然后在DepencencyInjection\AcmeDemoExtension.php中
class AcmeDemoExtension implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$widgets = $container->findTaggedServiceIds('acme.widget');
foreach ($widgets as $id => $tags) {
$definition = $container->getDefinition($id);
$definition->setArguments([$definition->getClass()]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后在工厂......
class AcmeWidgetFactory
{
//.....
public static function createWidget($class)
{
//.....
return new $class(/* dependencies */);
//.....
}
//.....
}
Run Code Online (Sandbox Code Playgroud)
因此,当您$this->get('acme.widget1')使用类名作为参数执行工厂方法时,最后会调用.Factory已经拥有所有依赖项并且知道类实例化的逻辑.所以它完成所有工作并返回所需的小部件实例.
这很简单。如果你要打电话
$nm = $container->get('app.newsletter_manager')
Run Code Online (Sandbox Code Playgroud)
那么时事通讯管理器将由工厂自动创建。