4

엔티티, 리포지토리 및 서비스 레이어가있는 도메인 모델이 잘 정의 된 MVC 응용 프로그램이 있습니다.다음 예에서 Service Locator가 안티 패턴 인 이유는 무엇입니까?

내 컨트롤러 내부에서 서비스 클래스를 인스턴스화하지 않아도되고 내 컨트롤러에 맞지 않는 논리를 사용하면, Service Locator 일종의 역할을하는 도우미를 만들었지 만 조금 읽은 후에도 깨달았습니다. 많은 DEVS :

서비스 탐지기가 실제로 안티 패턴이라고 말하면됩니다. 그러나 제 구현은 반 패턴이 아니라고 생각합니다.

서비스 로케이터를 anti-pattern으로 생각하는 이유는 종속성을 숨기기 때문입니다. 그러나 Entity Manager 만 종속성을 주입합니다 (이 종속성은 변경되지 않습니다). 서비스 인터페이스 (service interface))를 사용하여 서비스 로케이터 (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); 
    } 
} 

: 여기

내 코드입니다

//Some Controller 
$myService = $this->_helper->service('MyService'); //returns an instance of the class App\Domain\Service\MyService 
$result = $myService->doSomethingWithSomeData($this->getRequest()->getPost()); 
//etc... 
    :

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

    을 그리고 내 컨트롤러에서이 도우미를 사용하는 방법

  • 내 구현이 정확합니까?
  • 정말 안티 패턴입니까?
  • 내가 직면 할 수있는 문제는 무엇입니까?
  • 이 앤티 패턴을 없애기 위해 어떻게 코드를 리팩토링 할 수 있습니까?

답변

4

나는 당신이 만든 것이 서비스 로케이터 패턴을 구현하지 않는다고 생각합니다. 그렇게했다면 어딘가에 글로벌 "레지스트리"가 생길 것입니다.

기본적으로 factory 클래스 (App\Controller\Action\Helper\Service)는 종속성을 가지며 ctor를 통해 주입됩니다. 그래서 당신의 클래스는 그것의 의존성이 어디서 왔는지를 알지 못합니다. 또한 그것들을 생성하는 것에 대해서 책임을지지 않습니다 (이것은 좋은 것입니다!).

내가 틀렸다면 나를 수정하십시오. :)

BTW : 그렇기 때문에 종속성 주입 컨테이너를 지나쳐서는 안됩니다. 서비스 로케이터가됩니다.

+0

흠, 실제로 레지스트리와 같은 정적 클래스 인 HelperBroker를 고려하지 않은 채 글로벌 레지스트리가 없으므로 팩토리 클래스는 무엇입니까? : S 두 가지의 주요 차이점을 설명 할 수 있습니까? (공장 출동 대 서비스 찾기)? – JCM

+3

팩토리 클래스는 전달한 매개 변수를 기반으로 무언가를 생성합니다. 팩토리에 생성 할 것을 알려주면 항상 동일한 입력에 대해 동일한 출력을 반환합니다.예를 들어 EM (ctor를 통해)과 서비스 이름/네임 스페이스 (메소드를 통해)를 주입합니다. 어쩌면이 도움이 될 것입니다 : http://stackoverflow.com/questions/1557781/whats-the-difference-between-thependency-injection-and-service-locator-patte –

+3

@PhilippeGerber : 저는 공장을 구별하는 것이 가치가 있다고 생각합니다. 컨테이너. 전형적으로,'$ factory-> getObject ($ params)'형태의 반복적 인 호출은 요청 된 객체의 별개의 인스턴스를 생성 할 것이다. 대조적으로, 컨테이너는 보통 내부 레지스트리를 가지므로'$ container-> getObject ($ params) '형식의 모든 호출은 _same_ 인스턴스를 반환합니다. 그럼에도 불구하고 (1) 공장과 컨테이너는 모두 종속성 주입을 처리하는 배선 코드의 좋은 집이며 원래 질문의 예제는 공장으로 사용됩니다. –

관련 문제