4

私は、エンティティ、リポジトリ、およびサービスレイヤを持つ、ドメインモデルがよく定義されたMVCアプリケーションを持っています。次の例でサービスロケータがアンチパターンであるのはなぜですか?

私のコントローラー内でサービスクラスをインスタンス化しなくて済むように、私のコントローラーにはそれらのロジックに合わないロジックが混乱しないように、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... 
  • 私の実装は正しいですか?
  • 本当にアンチパターンですか?
  • 私は直面する可能性のある問題は何ですか?
  • このアンチパターンを削除するためにコードをリファクタリングするにはどうすればよいですか?

答えて

4

あなたが構築したものがサービスロケータパターンを実装しているとは思いません。もしあなたがそうしていれば、グローバルな「レジストリ」がどこかにあるでしょう。

私が見るのは基本的に、依存関係を持つ工場クラス(App\Controller\Action\Helper\Service)です。これはctorを介して注入されます。だからあなたのクラスは、その依存関係がどこから来たのか分からず、それを作成する責任もありません(これは良いことです)。

私が間違っている場合は私を修正してください。 :)

ところで、依存性注入コンテナを渡してはいけない理由もそうです。それはサービスロケータに変わります。

+0

Hum、実際にはグローバルレジストリはありません(HelperBrokerを使用せず、レジストリのように動作する静的クラスです)、私は工場クラスですか? :Sあなたは2つの間の主な違いを説明できますか(工場クラッセ対サービスロケータ)? – 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)工場とコンテナの両方が、依存性注入を扱う配線コードの良い家であり、(2)元の質問の例が工場として機能しているということです。 –

関連する問題