为什么服务定位器是以下示例中的反模式


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

我有一个MVC应用程序,它有一个定义良好的域模型,有实体、存储库和服务层。

为了避免在我的控制器中实例化我的服务类,从而用不适合它们的逻辑扰乱我的控制器,我创建了一个充当某种服务定位器的助手,但在阅读了一点之后,我意识到许多开发人员:

  • 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

假设服务定位器实际上是一个反模式。但我认为我的实现并不是一种反模式。

他们认为服务定位器是反模式的原因是因为它隐藏了依赖关系,然而,我在实例化服务定位器时注入了服务类所需的唯一依赖关系(实体管理器,这个依赖关系可能不会改变,因为它在服务接口的签名中)。

这是我的代码:

<?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 );
    }
}

向前端控制器注册Action Helper:

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

以及我如何在我的控制器中使用这个助手:

//Some Controller
$myService = $this->_helper->service( 'MyService' ); //returns an instance of the class App'Domain'Service'MyService
$result = $myService->doSomethingWithSomeData( $this->getRequest()->getPost() );
//etc...
  • 我的实施是正确的吗
  • 这真的是反模式吗
  • 我可能面临哪些问题
  • 如何重构代码以消除这种反模式,但继续使用功能

我不认为您构建的东西确实实现了服务定位器模式。如果你有这样的话,某个地方就会有一个全球性的"注册中心"。

我看到的基本上是一个带有依赖项的工厂类(App'Controller'Action'Helper'Service),这些依赖项是通过ctor注入的。因此,您的类不知道它的依赖项来自哪里,也不负责创建它们(这是一件好事!)。

如果我错了,请纠正我。:)

BTW:这也是为什么不应该传递依赖注入容器的原因。它变成了一个服务定位器。