私は、エンティティ、リポジトリ、およびサービスレイヤを持つ、ドメインモデルがよく定義されたMVCアプリケーションを持っています。次の例でサービスロケータがアンチパターンであるのはなぜですか?
私のコントローラー内でサービスクラスをインスタンス化しなくて済むように、私のコントローラーにはそれらのロジックに合わないロジックが混乱しないように、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
サービスロケータが実際にアンチパターンであるとします。しかし、私の実装は反パターンではないと私は思う。
サービスロケータをアンチパターンと見なす理由は、依存関係を隠すためですが、私は唯一の依存関係(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...
- 私の実装は正しいですか?
- 本当にアンチパターンですか?
- 私は直面する可能性のある問題は何ですか?
- このアンチパターンを削除するためにコードをリファクタリングするにはどうすればよいですか?
Hum、実際にはグローバルレジストリはありません(HelperBrokerを使用せず、レジストリのように動作する静的クラスです)、私は工場クラスですか? :Sあなたは2つの間の主な違いを説明できますか(工場クラッセ対サービスロケータ)? – JCM
ファクトリクラスは、渡すパラメータに基づいて何かを作成します。ファクトリには何を作成するかを指示し、同じ入力に対して常に同じ出力を返します。あなたの例では、EM(ctor経由)とサービス名/名前空間(メソッド経由)を注入します。たぶん、これは役立ちます:http://stackoverflow.com/questions/1557781/whats-the-difference-between-thependency-injection-and-service-locator-patte –
@PhilippeGerber:私はそれが工場をコンテナ。通常、 '$ factory-> getObject($ params)'の形式の繰り返し呼び出しは、要求されたオブジェクトの別個のインスタンスを生成します。対照的に、コンテナには通常、内部レジストリがあり、 '$ container-> getObject($ params)'の形式のすべての呼び出しが_same_インスタンスを返すようになっています。それでも、あなたは、(1)工場とコンテナの両方が、依存性注入を扱う配線コードの良い家であり、(2)元の質問の例が工場として機能しているということです。 –