代码之家  ›  专栏  ›  技术社区  ›  koseduhemak

Zend Framework 2-控制器通过(修改?)实例化服务工厂

  •  1
  • koseduhemak  · 技术社区  · 8 年前

    我有一个抽象服务类 SAbstract 由继承 ConcreteServiceA ConcreteServiceB 。现在我正在实例化 混凝土服务A 在我的控制器的工厂类中,并将服务注入我的控制器中。

    在控制器中的特定操作中,我想交换 混凝土服务A 具有 混凝土服务B 改变行为。因为它们有相同的接口(抽象类 S摘要 )我也可以将其注入我的控制器(服务是一种策略模式)。

    但我不想实例化 混凝土服务B 直接在控制器中保持代码干净(便于重构和交换行为)。

    一个可能的解决方案是为我的控制器创建第二个工厂 混凝土服务B 而不是 混凝土服务A 但后来我复制了很多不好的代码。。。 另一个解决方案是将这两个服务都注入我的控制器(但这“闻起来”像是坏代码)。

    a delegator factory 这样做的正确方法是什么?然后我必须在控制器中实现setter。。。

    有更好的方法吗?

    我试图以图表的方式形象化我的班级关系。

    AbstractService <|--<inherit>- ConcreteServiceA
    AbstractService <|--<inherit>- ConcreteServiceB
    Controller -<use>--> AbstractService
    Controller:ActionA -<use>--> ConcreteServiceA:exportAction()
    Controller:ActionB -<use>--> ConcreteServiceB:exportAction()
    
    1 回复  |  直到 8 年前
        1
  •  3
  •   AlexP    8 年前

    在控制器中的一个特定操作中,我想将ConcreteServiceA与ConcreteService B交换以更改行为。因为它们有相同的接口。

    您可以配置路由以使用不同的控制器 服务名称 对于每个动作;然后配置一个控制器工厂,以使用配置注入所需的服务。

    路由配置可能如下所示。

    'router' => [
        'routes' => [
            'foo' => [
                'type' => 'literal',
                'options' => [
                    'route' => '/foo',
                    'defaults' => [
                        'controller' => 'MyControllerWithFooService',
                        'action' => 'actionThatNeedsFooService',
                    ],
                ],
            ],
            'bar' => [
                'type' => 'literal',
                'options' => [
                    'route' => '/bar',
                    'defaults' => [
                        'controller' => 'MyControllerWithBarService',
                        'action' => 'actionThatNeedsBarService',
                    ],
                ],
            ],
        ],
    ]
    

    然后添加服务和控制器的配置。

    'app_config' => [
        'MyControllerWithFooService' => [
            'service_name' => 'FooService',
        ],
        'MyControllerWithFooService' => [
            'service_name' => 'BarService',
        ],
    ],
    'service_manager' => [
        'factories' => [
            'FooService' => 'FooServiceFactory'
            'BarService' => 'BarServiceFactory'
        ],
    ],
    'controllers' => [
        'factories' => [
            'MyControllerWithFooService' => 'MyControllerServiceFactory'
            'MyControllerWithBarService' => 'MyControllerServiceFactory'
        ],
    ]
    

    这个 MyControllerServiceFactory 可能很简单。

    class MyControllerServiceFactory
    {
        public function __invoke($controllerManager, $name, $requestedName)
        {
            $sm = $controllerManager->getServiceLocator();
    
            $config = $sm->get('config');
    
            if (empty($config['app_config'][$requestedName])) {
                throw new ServiceNotCreatedException('No config set!');
            }
    
            $serviceName = $config['app_config'][$requestedName]['service_name'];
            $service = $sm->get($serviceName);
    
            return new MyController($service);
        } 
    }