Почему сервисный локатор является анти-шаблоном в следующем примере? - PullRequest
4 голосов
/ 26 января 2012

У меня есть приложение MVC с четко определенной моделью предметной области, с сущностями, репозиториями и уровнем обслуживания.

Чтобы не создавать экземпляры классов обслуживания внутри контроллеров и, следовательно, не связывать контроллеры с логикойчто не устраивает их, я создал помощник, который действует как своего рода Service Locator , но, прочитав немного, я понял, что много разработчиков:

Скажите, что сервисный локатор на самом деле является антишаблоном.Но я думаю, что моя реализация не является анти-шаблоном.

Причина, по которой они считают Service Locator анти-шаблоном, заключается в том, что он скрывает зависимости, однако я внедряю единственную зависимость (Entity Manager, и этозависимость, вероятно, не изменится, поскольку она находится в сигнатуре интерфейса службы), требуемой классом службы, в момент создания экземпляра локатора службы.

Вот мой код:

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

Регистрация помощника действий с помощью переднего контроллера:

//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...
  • Моя реализация верна?
  • Это действительно анти-паттерн?
  • С какими возможными проблемами я могу столкнуться?
  • Как я могу реорганизовать свой код для устранения этого анти-паттерна, но продолжить сфункциональность?

1 Ответ

4 голосов
/ 26 января 2012

Я не думаю, что то, что вы создали, реализует шаблон локатора службы. Если бы у вас было так, где-то был бы глобальный «реестр».

То, что я вижу, это в основном фабричный класс (App\Controller\Action\Helper\Service) с зависимостями, которые вводятся через ctor. Так что ваш класс не знает, откуда появились его зависимости, и он также не отвечает за их создание (что хорошо!).

Поправь меня, если я ошибаюсь. :)

Кстати: это также причина, по которой вы не должны передавать свой контейнер внедрения зависимостей. Превращается в сервисный локатор.

...