为什么在Zend框架2使用服务管理?(Why use the Service Manager in

2019-08-08 11:32发布

可以说,我有一个服务:

namespace Helloworld\Service;

class GreetingService
{
    public function getGreeting()
    {
        if(date("H") <= 11)
            return "Good morning, world!";
        else if (date("H") > 11 && date("H") < 17)
            return "Hello, world!";
        else
            return "Good evening, world!";
    }
}

我为它创建一个可调用

public function getServiceConfig()
{
    return array(
        'invokables' => array(
            'greetingService'
                => 'Helloworld\Service\GreetingService'
        )
    );
}

然后在我的控制,我可以这样做:

public function indexAction()
{
    $greetingSrv = $this->getServiceLocator()
        ->get('greetingService');

    return new ViewModel(
        array('greeting' => $greetingSrv->getGreeting())
    );
}

据说这使控制器依赖于服务的(和的ServiceManager)

而更好的解决方案是为该服务创建工厂或的ServiceManager返回关闭和创建控制器二传手:

class IndexController extends AbstractActionController
{
    private $greetingService;

    public function indexAction()
    {

        return new ViewModel(
            array(
                'greeting' => $this->greetingService->getGreeting()
            )
        );
    }

    public function setGreetingService($service)
    {
        $this->greetingService = $service;
    }
}

'controllers' => array(
    'factories' => array(
        'Helloworld\Controller\Index' => function($serviceLocator) {
            $ctr = new Helloworld\Controller\IndexController();

            $ctr->setGreetingService(
                $serviceLocator->getServiceLocator()
                    ->get('greetingService')
            );

            return $ctr;
        }
    )
)

我的问题是为什么呢? 为什么第二种方法比第一种方法好? 和是什么意思,该controller is dependent of the service

谢谢

Answer 1:

所述ServiceManager是默认任何ZF2控制器内注射,因为它延长了AbstractController实现ServiceLocatorAwareInterface接口。

第二种方法具有一种形式的“ 冗余 ”,因为除了在已经进入到ServiceManager例如,当你需要共享你的控制器中为您服务,您需要配置为他们每个人的注射机构。 当你的控制器已经依赖面对面的人的的ServiceManager,这将使使用第一种方法并注册域名相关服务,以更有意义ServiceManager ,从而集中化访问服务层。

注意:答案以下的部分可能超越了问题的范围,但它的目的是提供原来的“隐藏”背景。

假设我们正在构建一个复杂的系统,在其中低耦合,可重用性和测试能力的提升。 我们的系统是一个多层次的,我们建立的一切,直到服务层。 请注意,到现在为止,我们没有考虑尚“MVC”网络层,甚至选择一个给定的框架。

在我们的服务层(因为它是在问题中提到了一个我会考虑这一层),我们假设我们通过原则的业务逻辑和对象图施工(或依赖分辨率)之间的分离。 因此,我们有可能是一对夫妇正在通过工厂构建复杂的服务。

现在,我们的业务层建成后,我们决定“插件”它上面ZF2。 当然,我们的服务应该从控制器访问,因为你的问题图示,但我们有比它做的方式更多。 但是,我们要避免冗余,并充分利用我们已经建成。 让我们假设以下工厂:

//The following class is a part of our Service layer
public class ComplexServiceFactory{

    private dependencyA;
    private dependencyB;

    public function buildComplexService()
    {
        $service = new ComplexService();
        $service->setDependencyA($this->dependecyA);
        $service->setDependencyB($this->dependecyB);
        return $service;
    }

}

我们现在要做的就是刚刚调整(实际上延长)我们的工厂,使之成为由可用ServiceManager逻辑。 这个类可以被视为使用“插入”我们的系统ZF2机制的一部分(它实际上是一个适配器 )

public class SMComplexServiceFactory extends ComplexServiceFactory implements
    Zend\ServiceManager\FactoryInterface
{

    public function createService(ServiceLocatorInterface $sm)
    {
        $this->setDependencyA($sm->get('dependecyA'));
        $this->setDependencyB($sm->get('dependecyB'));
        return parent::buildComplexService;
    }

}

通过这样做,我们没有抚养对象图施工的MVC层(否则这将是一个关注点分离违反和不必要的交叉层耦合)。 服务管理+我们的“改编”工厂类在某种意义上,我们的依赖解析机制。 事实是,我们的系统还是便携式,我们可以为另一个系统(另一个框架)例如opt和具有低依赖性面对面的人的MVC平台。



Answer 2:

非常有用的问题。 他曾多次提出。 我认为你可以得到一个准确的答案HERE



Answer 3:

要添加的东西@yechabbis答案:

对于工厂模式ServiceConfiguration确实是复杂的基础设施或者干脆不使用closures / callable functions里面的配置。 这有两个原因:

  • 可读性/清洁代码
  • 性能

设置里面的工厂模式getServiceConfig是好的,干净,快捷。 无类实例化,但是这样会在服务键呼叫。 但是,如果你使用的封闭模式或可调用函数设置服务,则这些类将永远被实例化,在每一个请求!

这可能仅仅是一个例子的事情,但你已经显示的代码也将最好地充当了ViewHelper



Answer 4:

我认为,第二种方法比较好,这是使得独立于GreetingService的控制器类。 当你想使用由控制器消耗另一个问候服务这种方法将是有益的。 你并不需要在所有改变控制器类的代码,而不是你做的,通过与该工厂的关闭改变服务经理。

相信这是控制或依赖注入,所有接线和构型反转的主要思想的类(在此情况下:控制器类)的外部完成。

所以,在我看来,这就是为什么第二种方式是更好的原因之一。



文章来源: Why use the Service Manager in Zend Framework 2?