У меня есть приложение MVC с хорошо известной моделью домена, с объектами, репозиториями и уровнем обслуживания.Почему локатор сервисов является Anti-Pattern в следующем примере?
Чтобы избежать необходимости создавать классы обслуживания внутри моих контроллеров и, таким образом, беспорядок мои контроллеры с логикой, которая им не подходит, я создал помощник, который действует как своего рода Service Locator, но после прочтения я понял что многие разработчики:
- 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
Скажите, что Service Locator на самом деле является анти-шаблоном. Но я считаю, что моя реализация не является анти-шаблоном.
Причина, по которой они считают, что локатор сервисов является анти-шаблоном, потому что он скрывает зависимости, однако я ввожу только зависимость (диспетчер сущностей, и эта зависимость, вероятно, не изменится, поскольку она находится в сигнатуре Service), требуемый классом службы, в то время, когда я создаю экземпляр Service Locator.
Вот мой код:
<?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);
}
}
Регистрация Действие Helper с Front Controller:
//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...
- Моя реализация верна?
- Это действительно анти-шаблон?
- Каковы возможные проблемы, с которыми я могу столкнуться?
- Как я могу реорганизовать свой код, чтобы устранить этот анти-шаблон, но продолжите функционировать?
Hum, Действительно, нет глобального реестра (без учета HelperBroker, который является статическим классом, который работает как реестр), так что у меня есть фабричный класс? : S Можете ли вы объяснить основные отличия между ними (заводская класса против локатора сервисов)? – JCM
Класс фабрики создает что-то, основанное на параметрах, которые вы передаете. Вы сообщаете фабрике, что создавать, и она всегда будет возвращать один и тот же результат для одного и того же ввода.В примере вы вводите EM (через ctor) и имя/пространство имен службы (посредством метода). Возможно, это помогает: http://stackoverflow.com/questions/1557781/whats-the-difference-between-the-dependency-injection-and-service-locator-patte –
@PhilippeGerber: Я думаю, что стоит отличать завод от контейнер. Как правило, повторные вызовы формы '$ factory-> getObject ($ params)' будут создавать отдельные экземпляры запрашиваемого объекта. Напротив, контейнер обычно имеет внутренний реестр, так что все вызовы формы '$ container-> getObject ($ params)' возвращают экземпляр _same_. Тем не менее, вы правы в том, что (1) обе фабрики и контейнеры являются хорошими домами для кода подключения, который обрабатывает инъекцию зависимостей, и (2) пример в исходном вопросе функционирует как фабрика. –