Why the Service Locator is a Anti-Pattern in the following example?

时光毁灭记忆、已成空白 提交于 2019-12-21 05:16:22

问题


I have a MVC application with a Domain Model well defined, with entities, repositories and a service layer.

To avoid having to instantiate my service classes inside my controllers, and thus, mess my controllers with logic that does not suit they, I created a helper that acts as a sort of Service Locator, but after reading a bit, I realized that many devs:

  • http://blog.tfnico.com/2011/04/dreaded-service-locator-pattern.html
  • http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
  • http://underground.infovark.com/2010/06/18/the-service-locator-pattern-is-the-new-global-variable/
  • http://www.andyfrench.info/2011/05/service-locator-anti-pattern_17.html

Say that the Service Locator is actually an anti-pattern. But I think my implementation is not an anti-pattern.

The reason they consider the Service Locator an anti-pattern, is because it hide dependencies, however, I inject the only dependency (the Entity Manager, and this dependency probably will not change, because it is in the signature of the Service interface) required by a service class, at the time I instantiate the Service Locator.

Here is my code:

<?php

namespace App\Controller\Action\Helper;
use Zend_Controller_Action_Helper_Abstract as Helper,
    Doctrine\ORM\EntityManager;

/**
 * Service Locator Helper
 * @author JCM
 */
class Service extends Helper {

    /**
     * The actual EntityManager
     * @var \Doctrine\ORM\EntityManager
     */
    private $entityManager;

    /**
     * Services Namespace
     * @var string
     */
    private $ns;

    /**
     * @param EntityManager $entityManager
     * @param string $ns The namespace where to find the services
     */
    public function __construct( EntityManager $entityManager, $ns )
    {
        $this->entityManager = $entityManager;
        $this->ns = $ns;
    }

    /**
     * @param string $serviceName
     * @param array $options
     * @param string $ns
     */
    public function direct( $serviceName, array $options = array(), $ns = null )
    {
        $ns = ( (!$ns) ? $this->ns : $ns ) . '\\';
        $class = $ns . $serviceName;

        return new $class( $this->entityManager, $options );
    }

    /**
     * @param EntityManager $entityManager
     */
    public function setEntityManager( EntityManager $entityManager )
    {
        $this->entityManager = $entityManager;
    }

    /**
     * @return \Doctrine\ORM\EntityManager
     */
    public function getEntityManager()
    {
        return $this->entityManager;
    }

    /**
     * @param string $name
     */
    public function __get( $name )
    {
        return $this->direct( $name );
    }
}

Registering the Action Helper with the Front Controller:

//inside some method in the bootstrap
HelperBroker::addHelper( new App\Controller\Action\Helper\Service( $entityManager, '\App\Domain\Service' ) );

And how I use this Helper in my controllers:

//Some Controller
$myService = $this->_helper->service( 'MyService' ); //returns an instance of the class App\Domain\Service\MyService
$result = $myService->doSomethingWithSomeData( $this->getRequest()->getPost() );
//etc...
  • My implementation is correct?
  • It really is an anti-pattern?
  • What are the possible problems that I might face?
  • How can I refactor my code to eliminate this anti-pattern, but continue with the functionality?

回答1:


I don't think that what you've built does implement the service locator pattern. If you had so, there would be a global "registry" somewhere.

What I see is basically a factory class (App\Controller\Action\Helper\Service) with dependencies, which are injected via the ctor. So your class does not know where its dependencies came from and it's also not responsible for creating them (which is a good thing!).

Correct me if I'm wrong. :)

BTW: That's also the reason why you should not pass around your dependency injection container. It turns into a service locator.



来源:https://stackoverflow.com/questions/9011787/why-the-service-locator-is-a-anti-pattern-in-the-following-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!